feat(addresses): improve address labeling and view-only handling
- Add expanded address icon picker with search, bottom-aligned actions, and improved modal sizing - Embed a pickaxe icon font subset and wire it into typography/address icon rendering - Track view-only shielded addresses and prevent sends from non-spendable z-addresses - Improve address transfer dialog sizing, max amount handling, and text clipping - Tune main header layout values in ui.toml - Update README, codebase overview, and third-party license documentation
This commit is contained in:
@@ -45,11 +45,12 @@ public:
|
||||
s_resultMsg.clear();
|
||||
s_success = false;
|
||||
|
||||
// Pre-fill amount with full source balance
|
||||
snprintf(s_amount, sizeof(s_amount), "%.8f", info.fromBalance);
|
||||
|
||||
// Default fee
|
||||
s_fee = 0.0001;
|
||||
|
||||
// Pre-fill with the maximum sendable amount so the dialog is valid
|
||||
// immediately without requiring the user to press Max.
|
||||
snprintf(s_amount, sizeof(s_amount), "%.8f", maxSendableAmount(info.fromBalance, s_fee));
|
||||
}
|
||||
|
||||
static void render() {
|
||||
@@ -57,7 +58,7 @@ public:
|
||||
|
||||
using namespace material;
|
||||
|
||||
if (BeginOverlayDialog(TR("transfer_funds"), &s_open, 480.0f, 0.94f)) {
|
||||
if (BeginOverlayDialog(TR("transfer_funds"), &s_open, 620.0f, 0.94f)) {
|
||||
float dp = Layout::dpiScale();
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
|
||||
@@ -104,18 +105,22 @@ public:
|
||||
ImGui::Spacing();
|
||||
ImGui::Spacing();
|
||||
|
||||
// Amount input
|
||||
// Amount input + Max button on same row without overflow
|
||||
Type().text(TypeStyle::Subtitle2, TR("amount"));
|
||||
ImGui::SetNextItemWidth(-1);
|
||||
{
|
||||
float spacing = ImGui::GetStyle().ItemSpacing.x;
|
||||
float maxBtnW = ImGui::CalcTextSize(TR("max")).x
|
||||
+ ImGui::GetStyle().FramePadding.x * 2.0f;
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - maxBtnW - spacing);
|
||||
}
|
||||
ImGui::InputText("##TransferAmt", s_amount, sizeof(s_amount),
|
||||
ImGuiInputTextFlags_CharsDecimal);
|
||||
|
||||
// Max button
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton(TR("max"))) {
|
||||
double maxAmt = s_info.fromBalance - s_fee;
|
||||
if (maxAmt < 0) maxAmt = 0;
|
||||
snprintf(s_amount, sizeof(s_amount), "%.8f", maxAmt);
|
||||
snprintf(s_amount, sizeof(s_amount), "%.8f",
|
||||
maxSendableAmount(s_info.fromBalance, s_fee));
|
||||
}
|
||||
ImGui::Spacing();
|
||||
|
||||
@@ -140,15 +145,15 @@ public:
|
||||
ImGui::Spacing();
|
||||
{
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), "%s: %.8f DRGX → %.8f DRGX",
|
||||
TR("sender_balance"), s_info.fromBalance, amountValid ? newFromBal : s_info.fromBalance);
|
||||
snprintf(buf, sizeof(buf), TR("sender_balance"),
|
||||
s_info.fromBalance, amountValid ? newFromBal : s_info.fromBalance);
|
||||
Type().textColored(TypeStyle::Caption,
|
||||
(amountValid && newFromBal < 1e-9) ? Warning() : OnSurfaceMedium(), buf);
|
||||
}
|
||||
{
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), "%s: %.8f DRGX → %.8f DRGX",
|
||||
TR("recipient_balance"), s_info.toBalance, amountValid ? newToBal : s_info.toBalance);
|
||||
snprintf(buf, sizeof(buf), TR("recipient_balance"),
|
||||
s_info.toBalance, amountValid ? newToBal : s_info.toBalance);
|
||||
Type().textColored(TypeStyle::Caption, OnSurfaceMedium(), buf);
|
||||
}
|
||||
|
||||
@@ -172,17 +177,32 @@ public:
|
||||
ImGui::Spacing();
|
||||
|
||||
// Buttons
|
||||
float btnW = 140.0f;
|
||||
float totalW = btnW * 2 + Layout::spacingMd();
|
||||
ImGui::SetCursorPosX((ImGui::GetContentRegionAvail().x - totalW) * 0.5f);
|
||||
const char* cancelLabel = TR("cancel");
|
||||
const char* confirmLabel = TR("confirm_transfer");
|
||||
const char* sendingLabel = TR("sending");
|
||||
ImFont* buttonFont = Type().button();
|
||||
float buttonFontSize = ScaledFontSize(buttonFont);
|
||||
float minBtnW = 120.0f * dp;
|
||||
float confirmMinW = 160.0f * dp;
|
||||
float buttonPadW = ImGui::GetStyle().FramePadding.x * 2.0f + 24.0f * dp;
|
||||
float cancelW = std::max(minBtnW,
|
||||
buttonFont->CalcTextSizeA(buttonFontSize, 1000.0f, 0.0f, cancelLabel).x + buttonPadW);
|
||||
float confirmTextW = std::max(
|
||||
buttonFont->CalcTextSizeA(buttonFontSize, 1000.0f, 0.0f, confirmLabel).x,
|
||||
buttonFont->CalcTextSizeA(buttonFontSize, 1000.0f, 0.0f, sendingLabel).x);
|
||||
float confirmW = std::max(confirmMinW, confirmTextW + buttonPadW);
|
||||
float totalW = cancelW + confirmW + Layout::spacingMd();
|
||||
float rowStartX = ImGui::GetCursorPosX();
|
||||
float contentW = ImGui::GetContentRegionAvail().x;
|
||||
ImGui::SetCursorPosX(rowStartX + std::max(0.0f, (contentW - totalW) * 0.5f));
|
||||
|
||||
if (TactileButton(TR("cancel"), ImVec2(btnW, 0))) {
|
||||
if (TactileButton(cancelLabel, ImVec2(cancelW, 0), buttonFont)) {
|
||||
s_open = false;
|
||||
}
|
||||
ImGui::SameLine(0, Layout::spacingMd());
|
||||
|
||||
ImGui::BeginDisabled(!amountValid || s_sending);
|
||||
if (TactileButton(s_sending ? TR("sending") : TR("confirm_transfer"), ImVec2(btnW, 0))) {
|
||||
if (TactileButton(s_sending ? sendingLabel : confirmLabel, ImVec2(confirmW, 0), buttonFont)) {
|
||||
s_sending = true;
|
||||
s_app->sendTransaction(s_info.fromAddr, s_info.toAddr,
|
||||
amount, s_fee, "",
|
||||
@@ -205,6 +225,11 @@ public:
|
||||
static void close() { s_open = false; }
|
||||
|
||||
private:
|
||||
static double maxSendableAmount(double balance, double fee) {
|
||||
double maxAmt = balance - fee;
|
||||
return maxAmt > 0.0 ? maxAmt : 0.0;
|
||||
}
|
||||
|
||||
static void renderAddressRow(const std::string& addr, double balance, bool isZ, float dp) {
|
||||
using namespace material;
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
@@ -228,22 +253,25 @@ private:
|
||||
dl->AddText(iconFont, iconFsz, ImVec2(mn.x + pad, mn.y + (h - iSz.y) * 0.5f), col, icon);
|
||||
|
||||
// Address (truncated)
|
||||
float textX = mn.x + pad + iSz.x + 8.0f * dp;
|
||||
std::string display = addr;
|
||||
if (display.size() > 42) display = display.substr(0, 18) + "..." + display.substr(display.size() - 14);
|
||||
ImFont* capFont = Type().caption();
|
||||
float capFsz = ScaledFontSize(capFont);
|
||||
dl->AddText(capFont, capFsz, ImVec2(textX, mn.y + (h * 0.5f - capFsz)), OnSurfaceMedium(), display.c_str());
|
||||
|
||||
// Balance (right-aligned)
|
||||
// Balance (right-aligned) — computed first so we know how much space address gets
|
||||
char balBuf[32];
|
||||
snprintf(balBuf, sizeof(balBuf), "%.8f DRGX", balance);
|
||||
ImFont* body = Type().body2();
|
||||
float bodyFsz = ScaledFontSize(body);
|
||||
ImVec2 balSz = body->CalcTextSizeA(bodyFsz, 1000.0f, 0.0f, balBuf);
|
||||
dl->AddText(body, bodyFsz, ImVec2(mx.x - pad - balSz.x, mn.y + (h - balSz.y) * 0.5f),
|
||||
float balX = mx.x - pad - balSz.x;
|
||||
dl->AddText(body, bodyFsz, ImVec2(balX, mn.y + (h - balSz.y) * 0.5f),
|
||||
balance > 0 ? OnSurface() : OnSurfaceDisabled(), balBuf);
|
||||
|
||||
float textX = mn.x + pad + iSz.x + 8.0f * dp;
|
||||
ImFont* capFont = Type().caption();
|
||||
float capFsz = ScaledFontSize(capFont);
|
||||
// Clip address text so it never overlaps the balance
|
||||
float addrMaxW = balX - textX - 8.0f * dp;
|
||||
dl->PushClipRect(ImVec2(textX, mn.y), ImVec2(textX + addrMaxW, mn.y + h), true);
|
||||
dl->AddText(capFont, capFsz, ImVec2(textX, mn.y + (h * 0.5f - capFsz)), OnSurfaceMedium(), addr.c_str());
|
||||
dl->PopClipRect();
|
||||
|
||||
ImGui::Dummy(ImVec2(w, h));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user