diff --git a/src/app.cpp b/src/app.cpp index c0b8ba0..05cc0e5 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -4635,6 +4635,7 @@ void App::renderSeedBackupDialog() sodium_memzero(&seed_backup_phrase_[0], seed_backup_phrase_.size()); seed_backup_phrase_.clear(); seed_backup_status_.clear(); + seed_backup_status_ok_ = true; seed_backup_fetch_started_ = false; seed_backup_loading_ = false; seed_backup_no_mnemonic_ = false; @@ -4707,7 +4708,9 @@ void App::renderSeedBackupDialog() ImGui::Spacing(); if (!seed_backup_status_.empty()) { ImGui::PushTextWrapPos(0.0f); - ImGui::TextColored(ui::material::SuccessVec4(), "%s", seed_backup_status_.c_str()); + ImGui::TextColored(seed_backup_status_ok_ ? ui::material::SuccessVec4() + : ImVec4(0.85f, 0.33f, 0.33f, 1.0f), + "%s", seed_backup_status_.c_str()); ImGui::PopTextWrapPos(); ImGui::Spacing(); } @@ -4724,6 +4727,7 @@ void App::renderSeedBackupDialog() const bool ok = util::Platform::writeFileAtomically(path, content, /*restrictPermissions=*/true); sodium_memzero(&content[0], content.size()); + seed_backup_status_ok_ = ok; // red when the write failed (was always green before) seed_backup_status_ = (ok ? std::string(TR("seed_backup_saved")) : std::string(TR("seed_backup_save_failed"))) + path; } diff --git a/src/app.h b/src/app.h index 5f7130d..745b482 100644 --- a/src/app.h +++ b/src/app.h @@ -1402,6 +1402,7 @@ private: // mnemonic) and is wiped with sodium_memzero when the dialog closes. std::string seed_backup_phrase_; std::string seed_backup_status_; + bool seed_backup_status_ok_ = true; // colour the status line by outcome (green save vs red fail) bool seed_backup_fetch_started_ = false; bool seed_backup_loading_ = false; bool seed_backup_no_mnemonic_ = false; diff --git a/src/app_security.cpp b/src/app_security.cpp index ea835bd..17d0145 100644 --- a/src/app_security.cpp +++ b/src/app_security.cpp @@ -1452,15 +1452,16 @@ void App::renderEncryptWalletDialog() { ImGui::TextUnformatted(TR("wiz_passphrase")); ImGui::PushItemWidth(-1); - ImGui::InputText("##enc_pass", encrypt_pass_buf_, sizeof(encrypt_pass_buf_), - ImGuiInputTextFlags_Password); + static bool s_showEncPass = false; + const ImGuiInputTextFlags encPwFlags = s_showEncPass ? 0 : ImGuiInputTextFlags_Password; + ImGui::InputText("##enc_pass", encrypt_pass_buf_, sizeof(encrypt_pass_buf_), encPwFlags); ImGui::PopItemWidth(); ImGui::TextUnformatted(TR("enc_confirm")); ImGui::PushItemWidth(-1); - ImGui::InputText("##enc_confirm", encrypt_confirm_buf_, sizeof(encrypt_confirm_buf_), - ImGuiInputTextFlags_Password); + ImGui::InputText("##enc_confirm", encrypt_confirm_buf_, sizeof(encrypt_confirm_buf_), encPwFlags); ImGui::PopItemWidth(); + ImGui::Checkbox(TR("enc_show_pass"), &s_showEncPass); // Strength meter bar { @@ -1508,8 +1509,15 @@ void App::renderEncryptWalletDialog() { } ImGui::Spacing(); - bool valid = strlen(encrypt_pass_buf_) >= 8 && - strcmp(encrypt_pass_buf_, encrypt_confirm_buf_) == 0; + const size_t encPassLen = strlen(encrypt_pass_buf_); + const bool encMatch = strcmp(encrypt_pass_buf_, encrypt_confirm_buf_) == 0; + bool valid = encPassLen >= 8 && encMatch; + // Say WHY the button is disabled, once the user has started typing (was silent before). + if (!valid && (encPassLen > 0 || strlen(encrypt_confirm_buf_) > 0)) { + const char* why = (encPassLen < 8) ? TR("enc_min_len") + : (!encMatch ? TR("enc_mismatch") : ""); + if (*why) ImGui::TextColored(ImVec4(1.0f, 0.7f, 0.3f, 1.0f), "%s", why); + } float btnW = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f; ImGui::BeginDisabled(!valid || encrypt_in_progress_); diff --git a/src/ui/windows/key_export_dialog.cpp b/src/ui/windows/key_export_dialog.cpp index b0c2104..e1c5adf 100644 --- a/src/ui/windows/key_export_dialog.cpp +++ b/src/ui/windows/key_export_dialog.cpp @@ -197,7 +197,7 @@ void KeyExportDialog::render(App* app) s_key = key; s_show_key = false; // Don't show by default } else { - s_error = error; + s_error = util::friendlyRpcError(error); } if (!key.empty()) sodium_memzero(&key[0], key.size()); // wipe the last transient copy s_fetching = false; @@ -223,7 +223,7 @@ void KeyExportDialog::render(App* app) s_key = key; s_show_key = true; // Viewing keys are less sensitive } else { - s_error = error; + s_error = util::friendlyRpcError(error); } if (!key.empty()) sodium_memzero(&key[0], key.size()); // wipe the last transient copy s_fetching = false; diff --git a/src/util/i18n.cpp b/src/util/i18n.cpp index ab39edc..90502bc 100644 --- a/src/util/i18n.cpp +++ b/src/util/i18n.cpp @@ -697,6 +697,9 @@ void I18n::loadBuiltinEnglish() // --- Encrypt / change-passphrase dialogs (settings) --- strings_["enc_desc"] = "Encrypting your wallet protects your private keys with a passphrase. After encryption, the daemon will restart."; strings_["enc_confirm"] = "Confirm:"; + strings_["enc_show_pass"] = "Show passphrase"; + strings_["enc_min_len"] = "Use at least 8 characters."; + strings_["enc_mismatch"] = "The passphrases don't match."; strings_["enc_encrypting"] = "Encrypting wallet..."; strings_["enc_wait"] = "Please wait, do not close the application."; strings_["enc_success"] = "Wallet encrypted successfully!";