From b217620d4023f4c31fba0aef5603fb6fbf19ed95 Mon Sep 17 00:00:00 2001
From: ZHU MINCHAO <48154958+MinchaoZhu@users.noreply.github.com>
Date: Wed, 4 Nov 2026 10:04:00 +0800
Subject: [PATCH] ui: skin web3 trade, stake and ponzi pages
---
src/Decentralized/TerminalWindow.cs | 65 +++++++++++++++++------------
1 file changed, 39 insertions(+), 26 deletions(-)
diff --git a/src/Decentralized/TerminalWindow.cs b/src/Decentralized/TerminalWindow.cs
index 2eeec6a..4fc1036 100644
--- a/src/Decentralized/TerminalWindow.cs
+++ b/src/Decentralized/TerminalWindow.cs
@@ -418,6 +418,7 @@ namespace Decentralized
}
private static readonly float[] PoolW = { 128f, 50f, 64f, 64f, 50f, 60f };
+ private static readonly TextAnchor[] PoolAligns = { TextAnchor.MiddleLeft, TextAnchor.MiddleRight, TextAnchor.MiddleRight, TextAnchor.MiddleRight, TextAnchor.MiddleRight, TextAnchor.MiddleRight };
/// 第三方收益池:日息、储备、时间锁、审计、我的存款,存入 / 取出(合约调用,签名)。是不是骗局看不见。
private static void YieldPools(CustomUIBuilder l, Wallet w, int day)
@@ -425,18 +426,27 @@ namespace Decentralized
var sc = Session.Data.Scams;
var pools = sc.Pools.Where(p => !p.Closed || p.Pending.Any(q => ChainAddress.Same(q.Wallet, w.Address))).ToList();
l.AddHeader(L.T("pool.h"));
- if (pools.Count == 0) { l.AddLabel(L.T("pool.none")); return; }
- TableHeader(l, PoolW, L.T("pool.col.name"), L.T("pool.col.rate"), L.T("pool.col.reserve"), L.T("pool.col.lock"), L.T("pool.col.audit"), L.T("pool.col.mine"));
+ if (pools.Count == 0) { l.AddLabel(L.T("pool.none"), "pool_none_dim"); return; }
+ TableHeader(l, PoolW.Sum() + 8f, PoolW, PoolAligns, L.T("pool.col.name"), L.T("pool.col.rate"), L.T("pool.col.reserve"), L.T("pool.col.lock"), L.T("pool.col.audit"), L.T("pool.col.mine"));
foreach (var p in pools)
{
var pp = p;
string mine = Fmt.Num(p.Of(w.Address)) + (p.Pending.Any(q => ChainAddress.Same(q.Wallet, w.Address)) ? "+" + L.T("pool.pending") : "");
- TableRow(l, PoolW, p.Name + (p.Closed ? " " + L.T("pool.closed") : ""), (p.Rate * 100).ToString("0", CultureInfo.InvariantCulture) + "%", Fmt.Num(p.Reserve), L.T(p.Timelock ? "pool.yes" : "pool.no"), L.T(p.Audited ? "pool.yes" : "pool.no"), mine);
+ TableRow(l, PoolW.Sum() + 8f, PoolW, PoolAligns,
+ new[] {
+ p.Name + (p.Closed ? " " + L.T("pool.closed") : ""),
+ (p.Rate * 100).ToString("0", CultureInfo.InvariantCulture) + "%",
+ Fmt.Num(p.Reserve),
+ L.T(p.Timelock ? "pool.yes" : "pool.no"),
+ L.T(p.Audited ? "pool.yes" : "pool.no"),
+ mine
+ });
if (p.Closed) continue;
l.BeginRow(4f);
l.AddButton(L.T("pool.deposit"), () => PoolCall(pp, true));
if (p.Of(w.Address) > 0) l.AddButton(L.T(p.Timelock ? "pool.withdraw.lock" : "pool.withdraw", Tuning.YieldLockDays), () => PoolCall(pp, false));
l.End();
+ l.AddSpace(2f);
}
}
@@ -554,12 +564,12 @@ namespace Decentralized
/// 理财页:两个子页。"存钱"是 NPC 开的第三方收益池,你存进去吃利息(可能是骗局);"自己发"是你当庄开高息理财(庞氏),下层的人往你这儿存。
private static void YieldPage(CustomUIBuilder b)
{
- b.BeginRow();
+ b.BeginRow(4f);
foreach (YieldTab t in Enum.GetValues(typeof(YieldTab)))
{
var tab = t;
string name = L.T("yield.sub." + t.ToString().ToLowerInvariant());
- b.AddButton(tab == _yieldTab ? $"[{name}]" : name, () => { _yieldTab = tab; _message = null; Open(); });
+ PledgerSkin.Pick(b, name, tab == _yieldTab, () => { _yieldTab = tab; _message = null; Open(); }, _picked);
}
b.End();
if (_yieldTab == YieldTab.Mine) { PonziPage(b); return; }
@@ -599,9 +609,9 @@ namespace Decentralized
l.AddLabel(L.T("ponzi.interest", Fmt.Num(pz.Pool * pz.Rate)));
l.AddLabel(L.T("ponzi.own", Fmt.Num(pz.OwnPaid)));
double risk = Ponzi.ReportChance(pz.Rate, pz.Pool, day);
- l.AddLabel(L.T("ponzi.wind", L.T(risk < 0.05 ? "ponzi.wind.low" : risk < 0.10 ? "ponzi.wind.mid" : "ponzi.wind.high")));
+ l.AddLabel(L.T("ponzi.wind", L.T(risk < 0.05 ? "ponzi.wind.low" : risk < 0.10 ? "ponzi.wind.mid" : "ponzi.wind.high")), risk >= 0.10 ? "ponzi_risk_note" : risk >= 0.05 ? "ponzi_risk_dim" : "ponzi_risk_ok");
}
- else l.AddLabel(pz.Done ? L.T("ponzi.done") : day < Tuning.PonziMinDay ? L.T("ponzi.early", Tuning.PonziMinDay) : L.T("ponzi.idle"));
+ else l.AddLabel(pz.Done ? L.T("ponzi.done") : day < Tuning.PonziMinDay ? L.T("ponzi.early", Tuning.PonziMinDay) : L.T("ponzi.idle"), "ponzi_status_dim");
}, r =>
{
if (pz.Open)
@@ -636,15 +646,15 @@ namespace Decentralized
}
if (pz.Done || day < Tuning.PonziMinDay) return;
r.AddHeader(L.T("ponzi.open"));
- r.BeginRow();
+ r.BeginRow(4f);
foreach (double rate in Tuning.PonziRates)
{
double rt = rate;
string t = (rate * 100).ToString("0", CultureInfo.InvariantCulture) + "%";
- r.AddButton(Math.Abs(rt - _ponziRate) < 1e-9 ? "[" + t + "]" : t, () => { _ponziRate = rt; Open(); });
+ PledgerSkin.Pick(r, t, Math.Abs(rt - _ponziRate) < 1e-9, () => { _ponziRate = rt; Open(); }, _picked);
}
r.End();
- r.AddLabel(L.T("ponzi.ad", Fmt.Num(Tuning.PonziAdCost)));
+ r.AddLabel(L.T("ponzi.ad", Fmt.Num(Tuning.PonziAdCost)), "ponzi_ad_dim");
r.AddButton(L.T("ponzi.start"), () =>
{
if (d.Hot.Avail(Assets.CRC) + 1e-9 < Tuning.PonziAdCost) { _message = L.T("ponzi.err"); Open(); return; }
@@ -1085,13 +1095,13 @@ namespace Decentralized
if (_web3Tab == Web3Tab.Mixer && !Unlock.MixerUnlocked) _web3Tab = Web3Tab.Trade;
if (_web3Tab == Web3Tab.Black && !Unlock.BlackUnlocked) _web3Tab = Web3Tab.Trade;
if (_web3Tab == Web3Tab.Predict && !PredictGame.Available(StoreStation.GetDayCounter())) _web3Tab = Web3Tab.Trade;
- b.BeginRow();
+ b.BeginRow(4f);
foreach (Web3Tab t in Enum.GetValues(typeof(Web3Tab)))
{
if ((t == Web3Tab.Mixer && !Unlock.MixerUnlocked) || (t == Web3Tab.Black && !Unlock.BlackUnlocked) || (t == Web3Tab.Predict && !PredictGame.Available(StoreStation.GetDayCounter()))) continue;
var tab = t;
string name = L.T("web3.sub." + t.ToString().ToLowerInvariant());
- b.AddButton(tab == _web3Tab ? $"[{name}]" : name, () => { _web3Tab = tab; _message = null; _edit = null; Open(); });
+ PledgerSkin.Pick(b, name, tab == _web3Tab, () => { _web3Tab = tab; _message = null; _edit = null; Open(); }, _picked);
}
b.End();
if (_web3Tab == Web3Tab.Stake) { StakePage(b); return; }
@@ -1108,10 +1118,10 @@ namespace Decentralized
Holdings(l, w, a => true);
l.AddSeparator();
l.AddLabel(L.T("wallet.total", Fmt.Credits(w.Value(Session.Price))));
- if (w.Taint > 0.5) l.AddLabel(L.T("wallet.taint", Fmt.Credits(w.Taint)));
+ if (w.Taint > 0.5) l.AddLabel(L.T("wallet.taint", Fmt.Credits(w.Taint)), "taint_note");
StableTable(l);
l.AddSeparator();
- CandleChart.AddPicker(l, "web3", Assets.PSC, Open);
+ CandleChart.AddPicker(l, "web3", Assets.PSC, Open, _picked);
}, r =>
{
r.AddHeader(L.T("trade.h"));
@@ -1528,15 +1538,15 @@ namespace Decentralized
int day = StoreStation.GetDayCounter();
r.AddSeparator();
r.AddLabel(L.T("black.desk.pair", Fmt.Num(Session.Price(Assets.Ponero))));
- r.AddLabel(L.T("black.desk.left", Fmt.Credits(d.Black.DeskLeft(day)), Fmt.Credits(Tuning.PoneroDailyCap)));
- r.BeginRow();
+ r.AddLabel(L.T("black.desk.left", Fmt.Credits(d.Black.DeskLeft(day)), Fmt.Credits(Tuning.PoneroDailyCap)), "desk_left_dim");
+ r.BeginRow(4f);
foreach (var a in new[] { Assets.PSC, Assets.CRT, Assets.CRA })
{
var asset = a;
- r.AddButton(asset == _deskAsset ? $"[{asset}]" : asset, () => { _deskAsset = asset; Open(); });
+ PledgerSkin.Pick(r, asset, asset == _deskAsset, () => { _deskAsset = asset; Open(); }, _picked);
}
r.End();
- r.BeginRow();
+ r.BeginRow(6f);
r.AddButton(L.T("black.desk.in"), () => { _deskIn = true; Swap(); });
r.AddButton(L.T("black.desk.out"), () => { _deskIn = false; Swap(); });
r.End();
@@ -1638,6 +1648,7 @@ namespace Decentralized
}
private static readonly float[] StakeW = { 110f, 90f, 200f };
+ private static readonly TextAnchor[] StakeAligns = { TextAnchor.MiddleLeft, TextAnchor.MiddleRight, TextAnchor.MiddleRight };
/// 质押页:革命军 CRA 质押池(日息、解锁排队)和平衡代币 SPARK 的铸销。都是合约调用,要在钱包上签名。
private static void StakePage(CustomUIBuilder b)
@@ -1649,18 +1660,19 @@ namespace Decentralized
Columns(b, l =>
{
l.AddHeader(L.T("stake.h"));
- l.AddLabel(L.T("stake.rate", (st.CraRate * 100).ToString("0.0", CultureInfo.InvariantCulture), Tuning.CraUnlockDays) + (st.CraSubsidyLow ? " " + L.T("stake.low") : ""));
+ l.AddLabel(L.T("stake.rate", (st.CraRate * 100).ToString("0.0", CultureInfo.InvariantCulture), Tuning.CraUnlockDays) + (st.CraSubsidyLow ? " " + L.T("stake.low") : ""), st.CraSubsidyLow ? "stake_low_note" : "stake_rate_dim");
l.AddLabel(L.T("stake.cra", Fmt.Num(st.Cra), StableStatus(st, Assets.CRA, day)));
l.AddSeparator();
- if (d.Staking.Lots.Count == 0) l.AddLabel(L.T("stake.none"));
+ if (d.Staking.Lots.Count == 0) l.AddLabel(L.T("stake.none"), "stake_none_dim");
else
{
- TableHeader(l, StakeW, L.T("stake.col.wallet"), L.T("stake.col.amount"), L.T("stake.col.queue"));
+ TableHeader(l, StakeW.Sum() + 8f, StakeW, StakeAligns, L.T("stake.col.wallet"), L.T("stake.col.amount"), L.T("stake.col.queue"));
foreach (var lot in d.Staking.Lots)
{
var ow = d.Own(lot.Wallet);
string queue = lot.Unlocking.Count == 0 ? "—" : string.Join(" ", lot.Unlocking.Select(u => Fmt.Num(u.Value) + L.T("stake.day", u.Key)));
- TableRow(l, StakeW, ow != null ? WalletWindow.NameOf(ow) : lot.Wallet, Fmt.Num(lot.Amount), queue);
+ TableRow(l, StakeW.Sum() + 8f, StakeW, StakeAligns,
+ new[] { ow != null ? WalletWindow.NameOf(ow) : lot.Wallet, Fmt.Num(lot.Amount), queue });
}
}
l.AddSeparator();
@@ -1668,16 +1680,17 @@ namespace Decentralized
}, r =>
{
r.AddHeader(L.T("stake.ops", WalletWindow.NameOf(w)));
- r.AddLabel(L.T("stake.avail", Fmt.Num(w.Avail(Assets.CRA)), Fmt.Num(d.Staking.Of(w.Address)?.Amount ?? 0)));
- r.AddLabel(L.T("stake.avail2", Fmt.Num(w.Avail(Assets.SPARK))));
+ r.AddLabel(L.T("stake.avail", Fmt.Num(w.Avail(Assets.CRA)), Fmt.Num(d.Staking.Of(w.Address)?.Amount ?? 0)), "stake_avail_dim");
+ r.AddLabel(L.T("stake.avail2", Fmt.Num(w.Avail(Assets.SPARK))), "stake_avail2_dim");
AmountRow(r);
- r.BeginRow();
+ r.AddSpace(4f);
+ r.BeginRow(6f);
r.AddButton(L.T("stake.do"), () => StakeCall(true));
r.AddButton(L.T("stake.undo"), () => StakeCall(false));
r.End();
r.AddSeparator();
r.AddHeader(L.T("spark.h"));
- r.BeginRow();
+ r.BeginRow(6f);
r.AddButton(L.T("spark.mint"), () => SparkCall(true));
r.AddButton(L.T("spark.burn"), () => SparkCall(false));
r.End();