feat(settings): migrate Seed phrase backup modal to the reference design
Phase 2 (second security modal), presentation-only + the review's one nit. Struct-form BlurFloat overlay (was the legacy positional overload); the phrase state's plain red warning -> material::DialogWarningHeader; StyledButtons -> TactileButtons with the Copy/Save/Close row and shared Close centered via PlaceOverlayDialogActions (the existing helper) and their separators dropped; success status now wraps. Already fully i18n'd. UNCHANGED (verified by the adversarial review): the closeAndWipe sodium_memzero of the 24-word phrase on every close path (Begin-false early return, outside-click/Esc teardown, phrase Close, shared Close), the async exportSeedPhrase fetch + its show_seed_backup_ callback guard, the atomic restricted-perms file-write + sodium_memzero of its content buffer, and copySecretToClipboard / RenderSeedWordGrid. No seed leak; Begin/EndOverlayDialog balanced on every return path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
32
src/app.cpp
32
src/app.cpp
@@ -3430,7 +3430,13 @@ void App::renderSeedBackupDialog()
|
||||
});
|
||||
}
|
||||
|
||||
if (!ui::material::BeginOverlayDialog(TR("seed_backup_title"), &show_seed_backup_, 540.0f, 0.94f)) {
|
||||
ui::material::OverlayDialogSpec ov;
|
||||
ov.title = TR("seed_backup_title");
|
||||
ov.p_open = &show_seed_backup_;
|
||||
ov.style = ui::material::OverlayStyle::BlurFloat;
|
||||
ov.cardWidth = 560.0f;
|
||||
ov.idSuffix = "seedbackup";
|
||||
if (!ui::material::BeginOverlayDialog(ov)) {
|
||||
if (seed_backup_fetch_started_) closeAndWipe();
|
||||
return;
|
||||
}
|
||||
@@ -3453,24 +3459,26 @@ void App::renderSeedBackupDialog()
|
||||
} else if (seed_backup_no_mnemonic_) {
|
||||
ImGui::TextWrapped("%s", TR("seed_backup_none"));
|
||||
} else if (!seed_backup_phrase_.empty()) {
|
||||
ImGui::TextWrapped("%s", TR("seed_backup_intro"));
|
||||
ui::material::DialogWarningHeader(TR("seed_backup_warning"));
|
||||
ImGui::Spacing();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ui::material::ReadableError());
|
||||
ImGui::TextWrapped("%s", TR("seed_backup_warning"));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::TextWrapped("%s", TR("seed_backup_intro"));
|
||||
ImGui::Spacing();
|
||||
ui::RenderSeedWordGrid(ui::SplitSeedWords(seed_backup_phrase_));
|
||||
ImGui::Spacing();
|
||||
if (!seed_backup_status_.empty()) {
|
||||
ImGui::PushTextWrapPos(0.0f);
|
||||
ImGui::TextColored(ui::material::SuccessVec4(), "%s", seed_backup_status_.c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::Spacing();
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ui::material::StyledButton(TR("seed_backup_copy"), ImVec2(120 * dp, 0))) {
|
||||
// Footer: Copy | Save | Close — centered as a group (no divider).
|
||||
const float cW = 120 * dp, sW = 150 * dp;
|
||||
ui::material::PlaceOverlayDialogActions(cW + sW + cW + ImGui::GetStyle().ItemSpacing.x * 2.0f);
|
||||
if (ui::material::TactileButton(TR("seed_backup_copy"), ImVec2(cW, 0))) {
|
||||
copySecretToClipboard(seed_backup_phrase_);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ui::material::StyledButton(TR("seed_backup_save"), ImVec2(150 * dp, 0))) {
|
||||
if (ui::material::TactileButton(TR("seed_backup_save"), ImVec2(sW, 0))) {
|
||||
std::string path = util::Platform::getConfigDir() + "/dragonx-seed-backup.txt";
|
||||
std::string content = seed_backup_phrase_ + "\n";
|
||||
const bool ok = util::Platform::writeFileAtomically(path, content,
|
||||
@@ -3480,7 +3488,7 @@ void App::renderSeedBackupDialog()
|
||||
: std::string(TR("seed_backup_save_failed"))) + path;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ui::material::StyledButton(TR("seed_backup_close"), ImVec2(120 * dp, 0))) {
|
||||
if (ui::material::TactileButton(TR("seed_backup_close"), ImVec2(cW, 0))) {
|
||||
closeAndWipe();
|
||||
ui::material::EndOverlayDialog();
|
||||
return;
|
||||
@@ -3492,8 +3500,10 @@ void App::renderSeedBackupDialog()
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
if (ui::material::StyledButton(TR("seed_backup_close"), ImVec2(120 * dp, 0))) {
|
||||
// Centered Close (no divider).
|
||||
const float cbW = 120 * dp;
|
||||
ui::material::PlaceOverlayDialogActions(cbW);
|
||||
if (ui::material::TactileButton(TR("seed_backup_close"), ImVec2(cbW, 0))) {
|
||||
closeAndWipe();
|
||||
}
|
||||
ui::material::EndOverlayDialog();
|
||||
|
||||
Reference in New Issue
Block a user