Compare commits
3
Commits
ae16c06d24
...
adf61e43d6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
adf61e43d6 | ||
|
|
fb281714f9 | ||
|
|
74c497922e |
+2
-2
@@ -999,7 +999,7 @@ std::string App::applyDaemonInitStatus(bool reachableButBusy)
|
||||
|
||||
std::string title = wt.title;
|
||||
const int h = daemon_controller_ ? daemon_controller_->lastBlockHeight() : -1;
|
||||
if (h > 0) title += " (Block " + std::to_string(h) + ")";
|
||||
if (h > 0) { char hb[48]; std::snprintf(hb, sizeof(hb), TR("warmup_block_fmt"), h); title += " "; title += hb; }
|
||||
|
||||
state_.warmup_status = title;
|
||||
state_.warmup_description = wt.description ? wt.description : "";
|
||||
@@ -1023,7 +1023,7 @@ void App::applyWarmupText(const std::string& rpcMessage)
|
||||
}
|
||||
// Append current block height from daemon output
|
||||
const int h = daemon_controller_ ? daemon_controller_->lastBlockHeight() : -1;
|
||||
if (h > 0) state_.warmup_status += " (Block " + std::to_string(h) + ")";
|
||||
if (h > 0) { char hb[48]; std::snprintf(hb, sizeof(hb), TR("warmup_block_fmt"), h); state_.warmup_status += " "; state_.warmup_status += hb; }
|
||||
connection_status_ = state_.warmup_status;
|
||||
}
|
||||
|
||||
|
||||
+15
-15
@@ -1521,7 +1521,7 @@ void App::renderEncryptWalletDialog() {
|
||||
|
||||
float btnW = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
|
||||
ImGui::BeginDisabled(!valid || encrypt_in_progress_);
|
||||
if (ui::material::TactileButton(TR("settings_encrypt_wallet"), ImVec2(btnW, 40))) {
|
||||
if (ui::material::TactileButton(TR("settings_encrypt_wallet"), ImVec2(btnW, 40.0f * ui::Layout::dpiScale()))) {
|
||||
std::string pass(encrypt_pass_buf_);
|
||||
enc_dlg_saved_passphrase_ = pass;
|
||||
memset(encrypt_pass_buf_, 0, sizeof(encrypt_pass_buf_));
|
||||
@@ -1533,7 +1533,7 @@ void App::renderEncryptWalletDialog() {
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ui::material::TactileButton(TR("cancel"), ImVec2(btnW, 40))) {
|
||||
if (ui::material::TactileButton(TR("cancel"), ImVec2(btnW, 40.0f * ui::Layout::dpiScale()))) {
|
||||
memset(encrypt_pass_buf_, 0, sizeof(encrypt_pass_buf_));
|
||||
memset(encrypt_confirm_buf_, 0, sizeof(encrypt_confirm_buf_));
|
||||
show_encrypt_dialog_ = false;
|
||||
@@ -1612,7 +1612,7 @@ void App::renderEncryptWalletDialog() {
|
||||
float btnW = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
|
||||
|
||||
ImGui::BeginDisabled(!pinValid || !hasPassphrase || pin_in_progress_);
|
||||
if (ui::material::TactileButton(TR("settings_set_pin"), ImVec2(btnW, 40))) {
|
||||
if (ui::material::TactileButton(TR("settings_set_pin"), ImVec2(btnW, 40.0f * ui::Layout::dpiScale()))) {
|
||||
pin_in_progress_ = true;
|
||||
enc_dlg_pin_status_.clear();
|
||||
std::string savedPass = enc_dlg_saved_passphrase_;
|
||||
@@ -1655,7 +1655,7 @@ void App::renderEncryptWalletDialog() {
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ui::material::TactileButton(TR("wiz_skip"), ImVec2(btnW, 40))) {
|
||||
if (ui::material::TactileButton(TR("wiz_skip"), ImVec2(btnW, 40.0f * ui::Layout::dpiScale()))) {
|
||||
if (!enc_dlg_saved_passphrase_.empty()) {
|
||||
util::SecureVault::secureZero(&enc_dlg_saved_passphrase_[0],
|
||||
enc_dlg_saved_passphrase_.size());
|
||||
@@ -1730,7 +1730,7 @@ void App::renderEncryptWalletDialog() {
|
||||
float btnW = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
|
||||
// Not while a PIN operation runs: PIN setup could verify and seal the OLD passphrase.
|
||||
ImGui::BeginDisabled(!valid || encrypt_in_progress_ || pin_in_progress_);
|
||||
if (ui::material::TactileButton(TR("change_pass_title"), ImVec2(btnW, 40))) {
|
||||
if (ui::material::TactileButton(TR("change_pass_title"), ImVec2(btnW, 40.0f * ui::Layout::dpiScale()))) {
|
||||
changePassphrase(std::string(change_old_pass_buf_),
|
||||
std::string(change_new_pass_buf_));
|
||||
}
|
||||
@@ -1739,7 +1739,7 @@ void App::renderEncryptWalletDialog() {
|
||||
ImGui::SameLine();
|
||||
// Cancel does what Esc/close does — dismiss without applying. Buffers are wiped by
|
||||
// the !show_change_passphrase_ cleanup block below.
|
||||
if (ui::material::TactileButton(TR("cancel"), ImVec2(btnW, 40))) {
|
||||
if (ui::material::TactileButton(TR("cancel"), ImVec2(btnW, 40.0f * ui::Layout::dpiScale()))) {
|
||||
show_change_passphrase_ = false;
|
||||
}
|
||||
EndOverlayDialog();
|
||||
@@ -1808,7 +1808,7 @@ void App::renderDecryptWalletDialog() {
|
||||
float btnW = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
|
||||
ImGui::BeginDisabled(!valid || decryptState.inProgress);
|
||||
// Decrypting stops and restarts the node: not while it is busy (refuseIfNodeBusy() only on a click).
|
||||
if ((ui::material::TactileButton(TR("settings_remove_encryption"), ImVec2(btnW, 40)) || (enterPressed && valid)) &&
|
||||
if ((ui::material::TactileButton(TR("settings_remove_encryption"), ImVec2(btnW, 40.0f * ui::Layout::dpiScale())) || (enterPressed && valid)) &&
|
||||
!refuseIfNodeBusy()) {
|
||||
std::string passphrase(decrypt_pass_buf_);
|
||||
memset(decrypt_pass_buf_, 0, sizeof(decrypt_pass_buf_));
|
||||
@@ -2017,7 +2017,7 @@ void App::renderDecryptWalletDialog() {
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ui::material::TactileButton(TR("cancel"), ImVec2(btnW, 40))) {
|
||||
if (ui::material::TactileButton(TR("cancel"), ImVec2(btnW, 40.0f * ui::Layout::dpiScale()))) {
|
||||
memset(decrypt_pass_buf_, 0, sizeof(decrypt_pass_buf_));
|
||||
show_decrypt_dialog_ = false;
|
||||
}
|
||||
@@ -2132,7 +2132,7 @@ void App::renderDecryptWalletDialog() {
|
||||
ImGui::TextWrapped("%s", TR("decrypt_success_desc"));
|
||||
|
||||
ImGui::Spacing();
|
||||
if (ui::material::TactileButton(TR("close"), ImVec2(-1, 40))) {
|
||||
if (ui::material::TactileButton(TR("close"), ImVec2(-1, 40.0f * ui::Layout::dpiScale()))) {
|
||||
show_decrypt_dialog_ = false;
|
||||
}
|
||||
|
||||
@@ -2149,11 +2149,11 @@ void App::renderDecryptWalletDialog() {
|
||||
|
||||
ImGui::Spacing();
|
||||
float btnW = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
|
||||
if (ui::material::TactileButton(TR("try_again"), ImVec2(btnW, 40))) {
|
||||
if (ui::material::TactileButton(TR("try_again"), ImVec2(btnW, 40.0f * ui::Layout::dpiScale()))) {
|
||||
wallet_security_workflow_.reset();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ui::material::TactileButton(TR("close"), ImVec2(btnW, 40))) {
|
||||
if (ui::material::TactileButton(TR("close"), ImVec2(btnW, 40.0f * ui::Layout::dpiScale()))) {
|
||||
show_decrypt_dialog_ = false;
|
||||
}
|
||||
}
|
||||
@@ -2219,7 +2219,7 @@ void App::renderPinDialogs() {
|
||||
float btnW = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
|
||||
// Not while a passphrase change runs: it could land after the old passphrase is verified.
|
||||
ImGui::BeginDisabled(!valid || pin_in_progress_ || encrypt_in_progress_);
|
||||
if (ui::material::TactileButton(TR("settings_set_pin"), ImVec2(btnW, 40))) {
|
||||
if (ui::material::TactileButton(TR("settings_set_pin"), ImVec2(btnW, 40.0f * ui::Layout::dpiScale()))) {
|
||||
pin_in_progress_ = true;
|
||||
pin_status_ = TR("sec_verifying_passphrase");
|
||||
|
||||
@@ -2292,7 +2292,7 @@ void App::renderPinDialogs() {
|
||||
ImGui::SameLine();
|
||||
// Cancel does what Esc/close does — dismiss without applying. Buffers are wiped by
|
||||
// the !show_pin_setup_ cleanup block below.
|
||||
if (ui::material::TactileButton(TR("cancel"), ImVec2(btnW, 40))) {
|
||||
if (ui::material::TactileButton(TR("cancel"), ImVec2(btnW, 40.0f * ui::Layout::dpiScale()))) {
|
||||
show_pin_setup_ = false;
|
||||
}
|
||||
EndOverlayDialog();
|
||||
@@ -2346,7 +2346,7 @@ void App::renderPinDialogs() {
|
||||
strcmp(pin_buf_, pin_confirm_buf_) == 0;
|
||||
|
||||
ImGui::BeginDisabled(!valid || pin_in_progress_);
|
||||
if (ui::material::TactileButton(TR("settings_change_pin"), ImVec2(-1, 40))) {
|
||||
if (ui::material::TactileButton(TR("settings_change_pin"), ImVec2(-1, 40.0f * ui::Layout::dpiScale()))) {
|
||||
pin_in_progress_ = true;
|
||||
pin_status_ = TR("sec_changing_pin");
|
||||
std::string oldPin(pin_old_buf_);
|
||||
@@ -2411,7 +2411,7 @@ void App::renderPinDialogs() {
|
||||
ImGui::Spacing();
|
||||
bool valid = strlen(pin_old_buf_) >= 4;
|
||||
ImGui::BeginDisabled(!valid || pin_in_progress_);
|
||||
if (ui::material::TactileButton(TR("settings_remove_pin"), ImVec2(-1, 40))) {
|
||||
if (ui::material::TactileButton(TR("settings_remove_pin"), ImVec2(-1, 40.0f * ui::Layout::dpiScale()))) {
|
||||
pin_in_progress_ = true;
|
||||
pin_status_ = TR("sec_verifying_pin");
|
||||
std::string oldPin(pin_old_buf_);
|
||||
|
||||
@@ -141,6 +141,14 @@ public:
|
||||
double newFromBal = s_info.fromBalance - totalDeduct;
|
||||
double newToBal = s_info.toBalance + amount;
|
||||
bool amountValid = amount > 0 && totalDeduct <= s_info.fromBalance;
|
||||
// Mirror the Send tab's guards (this dialog previously enabled Confirm on amount alone, so a
|
||||
// disconnected / syncing / locked wallet would fail only at submit). These are own-address
|
||||
// moves, but gating is strictly more restrictive — the transfer logic below is unchanged.
|
||||
const auto& ws = s_app->getWalletState();
|
||||
const bool connected = s_app->isConnected();
|
||||
const bool syncing = ws.sync.syncing;
|
||||
const bool liteLocked = s_app->liteWallet() && ws.isLocked();
|
||||
const bool canTransfer = amountValid && !s_sending && connected && !syncing && !liteLocked;
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
@@ -167,6 +175,19 @@ public:
|
||||
ImGui::TextWrapped("%s", TR("insufficient_funds"));
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
if (amount <= 0.0) {
|
||||
ImGui::Spacing();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::ColorConvertU32ToFloat4(Error()));
|
||||
ImGui::TextWrapped("%s", TR("send_tooltip_enter_amount"));
|
||||
ImGui::PopStyleColor();
|
||||
} else if (amountValid && (!connected || syncing || liteLocked)) {
|
||||
ImGui::Spacing();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::ColorConvertU32ToFloat4(Warning()));
|
||||
ImGui::TextWrapped("%s", !connected ? TR("send_tooltip_not_connected")
|
||||
: syncing ? TR("send_tooltip_syncing")
|
||||
: TR("transfer_tooltip_locked"));
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
if (amountValid && newFromBal < 1e-9) {
|
||||
ImGui::Spacing();
|
||||
// Full-balance send: same warning-icon treatment as the de-shielding header above,
|
||||
@@ -204,13 +225,13 @@ public:
|
||||
bool outConfirm = false;
|
||||
bool outClose = false;
|
||||
DialogActionFooter(s_sending ? sendingLabel : confirmLabel,
|
||||
amountValid && !s_sending,
|
||||
canTransfer,
|
||||
cancelLabel, outConfirm, outClose, btnW);
|
||||
|
||||
if (outClose) {
|
||||
s_open = false;
|
||||
}
|
||||
if (outConfirm) {
|
||||
if (outConfirm && canTransfer) { // re-check live state (the dialog persists across frames)
|
||||
s_sending = true;
|
||||
s_app->sendTransaction(s_info.fromAddr, s_info.toAddr,
|
||||
amount, s_fee, "",
|
||||
@@ -296,12 +317,19 @@ private:
|
||||
Type().textColored(TypeStyle::Caption, OnSurfaceMedium(), TR("transfer_sent_desc"));
|
||||
ImGui::Spacing();
|
||||
{
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), TR("shield_operation_id"),
|
||||
s_resultMsg.size() > 40
|
||||
? (s_resultMsg.substr(0, 20) + "..." + s_resultMsg.substr(s_resultMsg.size() - 10)).c_str()
|
||||
: s_resultMsg.c_str());
|
||||
// The result is a TRANSACTION id, not an "Operation ID" — label it correctly and make
|
||||
// it copyable.
|
||||
std::string disp = s_resultMsg.size() > 40
|
||||
? (s_resultMsg.substr(0, 20) + "..." + s_resultMsg.substr(s_resultMsg.size() - 10))
|
||||
: s_resultMsg;
|
||||
char buf[160];
|
||||
snprintf(buf, sizeof(buf), TR("transfer_txid_label"), disp.c_str());
|
||||
Type().textColored(TypeStyle::Caption, OnSurfaceDisabled(), buf);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton(TR("grpb_copy"))) {
|
||||
ImGui::SetClipboardText(s_resultMsg.c_str());
|
||||
Notifications::instance().info(TR("copied_to_clipboard"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ImGui::Spacing();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "balance_recent_tx.h"
|
||||
#include "../../config/version.h"
|
||||
#include "../../util/text_format.h"
|
||||
#include "../../util/i18n.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
@@ -23,12 +24,22 @@ std::string recentTimeAgo(int64_t timestamp)
|
||||
{
|
||||
return util::formatTimeAgoShort(timestamp);
|
||||
}
|
||||
|
||||
// Translated type label (the data layer's getTypeDisplay() returns raw English). Never leak a raw RPC
|
||||
// category: anything unrecognized (including "shield") falls back to a generic "Transaction".
|
||||
std::string recentTypeLabel(const std::string& type)
|
||||
{
|
||||
if (type == "send") return TR("sent_type");
|
||||
if (type == "receive") return TR("received_label");
|
||||
if (type == "mined" || type == "generate" || type == "immature") return TR("mined_type");
|
||||
return TR("tx_type_generic");
|
||||
}
|
||||
}
|
||||
|
||||
RecentTxDisplay buildRecentTxDisplay(const TransactionInfo& tx, int addressMaxLen)
|
||||
{
|
||||
return {
|
||||
tx.getTypeDisplay(),
|
||||
recentTypeLabel(tx.type),
|
||||
util::truncateMiddle(tx.address, addressMaxLen),
|
||||
formatRecentAmount(tx.type, tx.amount),
|
||||
recentTimeAgo(tx.timestamp)
|
||||
|
||||
@@ -1431,7 +1431,7 @@ static void mktDrawPairSelector(App* app, const std::vector<data::ExchangeInfo>&
|
||||
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
||||
Type().textColored(TypeStyle::Caption, OnSurfaceDisabled(), TR("market_attribution"));
|
||||
if (!market.last_updated.empty()) {
|
||||
ImGui::SameLine(0, 12);
|
||||
ImGui::SameLine(0, 12.0f * Layout::dpiScale());
|
||||
snprintf(buf, sizeof(buf), TR("market_updated"), market.last_updated.c_str());
|
||||
Type().textColored(TypeStyle::Caption, OnSurfaceDisabled(), buf);
|
||||
}
|
||||
|
||||
@@ -957,6 +957,8 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo&
|
||||
material::Tooltip("%s", isMiningActive ? TR("mining_stopping_tooltip") : TR("mining_starting_tooltip"));
|
||||
else if (isSyncing && !s_pool_mode)
|
||||
material::Tooltip(TR("mining_syncing_tooltip"), state.sync.verification_progress * 100.0);
|
||||
else if (!s_pool_mode && !poolStillRunning && !app->isConnected())
|
||||
material::Tooltip("%s", TR("mining_not_connected_tooltip")); // was falling through to "Start Mining" on a dead button
|
||||
else if (poolBlockedBySolo)
|
||||
material::Tooltip("%s", TR("mining_stop_solo_for_pool"));
|
||||
else if (poolNeedsPayout)
|
||||
|
||||
@@ -74,7 +74,9 @@ void QRPopupDialog::render(App* app)
|
||||
const float addrBoxW = ImGui::CalcTextSize(chunkedAddr.c_str()).x + addrPadX * 2.0f + 2.0f;
|
||||
// The BlurFloat overlay card insets content by 28px per side (draw_helpers BeginOverlayDialog); add
|
||||
// that (+ a little slack) so the address box fits on one line under its label instead of wrapping.
|
||||
const float wantW = addrBoxW + 28.0f * 2.0f + 12.0f;
|
||||
// Scale the overlay inset (BeginOverlayDialog insets 28 LOGICAL px/side) into the same scaled space
|
||||
// as addrBoxW before the /dp conversion below, so the address box doesn't wrap at HiDPI.
|
||||
const float wantW = addrBoxW + (28.0f * 2.0f + 12.0f) * dp;
|
||||
const float maxW = 0.85f * ImGui::GetMainViewport()->Size.x;
|
||||
const float cardW = (wantW < maxW ? wantW : maxW) / dp;
|
||||
material::OverlayDialogSpec ov;
|
||||
|
||||
@@ -1118,6 +1118,8 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["confirm_transfer"] = "Confirm Transfer";
|
||||
strings_["transfer_sent"] = "Transfer Sent";
|
||||
strings_["transfer_sent_desc"] = "Your transfer has been submitted to the network.";
|
||||
strings_["transfer_txid_label"] = "Transaction ID: %s";
|
||||
strings_["transfer_tooltip_locked"] = "Wallet is locked — unlock it to transfer";
|
||||
strings_["transfer_failed"] = "Transfer Failed";
|
||||
|
||||
// Misc dialog strings
|
||||
@@ -1223,6 +1225,7 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["shielded_self_type"] = "Shielded";
|
||||
strings_["immature_type"] = "Immature";
|
||||
strings_["mined_type"] = "Mined";
|
||||
strings_["tx_type_generic"] = "Transaction";
|
||||
strings_["mature"] = "Mature";
|
||||
strings_["copy_txid"] = "Copy TxID";
|
||||
strings_["view_details"] = "View Details";
|
||||
@@ -1944,6 +1947,7 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["toast_finish_send_first"] = "Finish or cancel the pending send before switching wallets.";
|
||||
strings_["toast_rescan_complete"] = "Blockchain rescan complete.";
|
||||
strings_["toast_rescan_from_fmt"] = "Rescanning the blockchain from block %d — this can take a while.";
|
||||
strings_["warmup_block_fmt"] = "(Block %d)";
|
||||
strings_["toast_solo_unavailable_lite"] = "Solo mining isn't available in the lite wallet.";
|
||||
strings_["toast_pool_unavailable"] = "Pool mining isn't available in this build.";
|
||||
strings_["toast_no_address_generate_z"] = "No wallet address yet — generate a shielded (Z) address in the Receive tab.";
|
||||
@@ -2354,6 +2358,7 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["mining_stopping"] = "Stopping...";
|
||||
strings_["mining_stopping_tooltip"] = "Miner is stopping...";
|
||||
strings_["mining_syncing_tooltip"] = "Blockchain is syncing...";
|
||||
strings_["mining_not_connected_tooltip"] = "Not connected to the node. Wait for the daemon to connect before mining.";
|
||||
strings_["mining_to_save"] = "to save";
|
||||
strings_["mining_today"] = "Today";
|
||||
strings_["mining_uptime"] = "Uptime";
|
||||
|
||||
Reference in New Issue
Block a user