终端只重建内容区并合并同帧刷新;平台费页文案;按住签名随 Gas 档位缩短

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ZHU MINCHAOandClaude Sonnet 5.5 committed 2026-11-05 21:57:15 +08:00
1 parent 876a8c4daa
commit f5beeea900
14 files changed
+138 -28

No files matched your search

+6
View File
@@ -1,5 +1,11 @@
# Changelog
## 未发布
- 终端刷新只重建页签栏、滚动内容和消息行,窗口框架和滚动视图保留:滚动位置不再回到顶部(换页或换子页签时才回顶);同一帧里的多次刷新合并成一次。
- 货架付平台费页:标题“支付平台费”,去掉“付款币种”字样。
- 按住 ✓ 签名的时间随 Gas 档位变化:快档 0.6 秒、普通档 1.2 秒、慢档 1.8 秒(`Tuning.TxHoldSecs` × 档位速度倍数)。
## 1.0.0-rc8
- 灰网商店卖货重构:卖货默认是已上架的橱窗(同一商品聚合成一张卡,同一商品倍率相同);“上架更多”进备货页,左边选标价倍率,货架卡片显示聚合库存,用 − / + 调整本次要上架的数量;右下角“货架 N”进付费页,在清单里核对、选币付上架费后才上架。橱窗里每点一次“下架”预备 +1,右下角“确定下架 N”确认,货回储藏区,上架费不退。上架上限改为同时最多 6 种、每种最多 5 件(原来总共 10 件);倍率表不再显示成交天数。
+2
View File
@@ -182,6 +182,8 @@ namespace Decentralized.Domain
public const double TxFeeSlow = 0.5, TxFeeNormal = 1.5, TxFeeFast = 4, TxCongestedFeeMult = 4;
/// <summary>Gas 档位的确认速度倍数(时间乘它):Gas 越高确认越快、进度条走得越快;Poinbase 出金固定普通档。</summary>
public const double TxSpeedSlow = 1.5, TxSpeedNormal = 1, TxSpeedFast = 0.5;
/// <summary>PLEDGER 按住 ✓ 签名的基础秒数(普通档),乘档位速度倍数:快档更短、慢档更长。</summary>
public const double TxHoldSecs = 1.2;
/// <summary>Gas 价格指数:以 GasPeriod 天为周期正弦涨跌,振幅 GasAmp(0.5×–1.5×),每天再乘 1 ± GasNoise 的随机波动。</summary>
public const int TxGasPeriod = 7;
public const double TxGasAmp = 0.5, TxGasNoise = 0.15;
+1
View File
@@ -399,6 +399,7 @@ namespace Decentralized.Domain
["TxGasNoise"] = Tuning.TxGasNoise,
["TxGasPeriod"] = Tuning.TxGasPeriod,
["TxHijackChance"] = Tuning.TxHijackChance,
["TxHoldSecs"] = Tuning.TxHoldSecs,
["TxPhishChance"] = Tuning.TxPhishChance,
["TxPoisonChance"] = Tuning.TxPoisonChance,
["TxPoisonDelayMax"] = Tuning.TxPoisonDelayMax,
@@ -762,7 +762,6 @@ ponzi.early,Schneeballsysteme können ab Tag {0} aufgelegt werden.
bpay.h,Zahlung
bpay.qty,Menge
bpay.total,Insgesamt {0} Credits
bpay.coin,Zahlen mit (vom Verkäufer akzeptiert)
bpay.need,Zu zahlen: {0} {1} Wallet-Guthaben: {2}
bpay.invoice,Rechnung erstellen
bpay.swap.h,Auto-Umtausch in {0}
@@ -950,3 +949,4 @@ explorer.col.day,Tag
explorer.day,Tag {0}
explorer.pool,RatDigg-Pool
explorer.desk,Ponero-Wechselstube
black.fee.pay,Einstellgebühr zahlen
1 # Probably Decentralized localization table: German (de)
762 bpay.h
763 bpay.qty
764 bpay.total
bpay.coin
765 bpay.need
766 bpay.invoice
767 bpay.swap.h
949 explorer.day
950 explorer.pool
951 explorer.desk
952 black.fee.pay
@@ -762,7 +762,6 @@ ponzi.early,High-yield schemes can be issued from day {0}.
bpay.h,Payment
bpay.qty,Quantity
bpay.total,Total {0} credits
bpay.coin,Pay with (coins the seller takes)
bpay.need,Pay {0} {1} wallet balance {2}
bpay.invoice,Create invoice
bpay.swap.h,Auto-convert to {0}
@@ -950,3 +949,4 @@ explorer.col.day,Day
explorer.day,Day {0}
explorer.pool,RatDigg pool
explorer.desk,Ponero desk
black.fee.pay,Pay listing fee
1 # Probably Decentralized localization table: English (en)
762 bpay.h
763 bpay.qty
764 bpay.total
bpay.coin
765 bpay.need
766 bpay.invoice
767 bpay.swap.h
949 explorer.day
950 explorer.pool
951 explorer.desk
952 black.fee.pay
@@ -762,7 +762,6 @@ ponzi.early,Los esquemas Ponzi se pueden emitir a partir del día {0}.
bpay.h,Pago
bpay.qty,Cantidad
bpay.total,Total en créditos: {0}
bpay.coin,Pagar con (monedas que acepta el vendedor)
bpay.need,Pagar {0} {1} saldo en billetera {2}
bpay.invoice,Crear factura
bpay.swap.h,Autoconversión a {0}
@@ -950,3 +949,4 @@ explorer.col.day,Día
explorer.day,Día {0}
explorer.pool,pool de RatDigg
explorer.desk,mesa Ponero
black.fee.pay,Pagar la tarifa de publicación
1 # Probably Decentralized localization table: Spanish (es)
762 bpay.h
763 bpay.qty
764 bpay.total
bpay.coin
765 bpay.need
766 bpay.invoice
767 bpay.swap.h
949 explorer.day
950 explorer.pool
951 explorer.desk
952 black.fee.pay
@@ -762,7 +762,6 @@ ponzi.early,Les systèmes de Ponzi peuvent être lancés dès le jour {0}.
bpay.h,Paiement
bpay.qty,Quantité
bpay.total,Total : {0} crédits
bpay.coin,Payer en (monnaies acceptées par le vendeur)
bpay.need,Payer {0} {1} solde du portefeuille : {2}
bpay.invoice,Créer une facture
bpay.swap.h,Conversion auto en {0}
@@ -950,3 +949,4 @@ explorer.col.day,Jour
explorer.day,Jour {0}
explorer.pool,pool RatDigg
explorer.desk,bureau Ponero
black.fee.pay,Payer les frais de mise en vente
1 # Probably Decentralized localization table: French (fr)
762 bpay.h
763 bpay.qty
764 bpay.total
bpay.coin
765 bpay.need
766 bpay.invoice
767 bpay.swap.h
949 explorer.day
950 explorer.pool
951 explorer.desk
952 black.fee.pay
@@ -762,7 +762,6 @@ ponzi.early,ポンジ・スキームは{0}日目から発行可能。
bpay.h,支払い
bpay.qty,数量
bpay.total,合計{0}クレジット相当
bpay.coin,支払通貨(売り手の対応通貨)
bpay.need,支払額 {0} {1} ウォレット残高 {2}
bpay.invoice,請求書を作成
bpay.swap.h,{0} への自動変換
@@ -950,3 +949,4 @@ explorer.col.day,日
explorer.day,{0}日目
explorer.pool,RatDiggプール
explorer.desk,Ponero両替所
black.fee.pay,出品手数料を支払う
Can't render this file because it contains an unexpected character in line 488 and column 24.
@@ -762,7 +762,6 @@ ponzi.early,Piramidy finansowe można tworzyć od dnia {0}.
bpay.h,Płatność
bpay.qty,Ilość
bpay.total,Razem (kredyty): {0}
bpay.coin,Moneta (przyjmowana przez sprzedającego)
bpay.need,Do zapłaty: {0} {1} saldo portfela: {2}
bpay.invoice,Utwórz rachunek
bpay.swap.h,Autokonwersja na {0}
@@ -950,3 +949,4 @@ explorer.col.day,Dzień
explorer.day,Dzień {0}
explorer.pool,pula RatDigg
explorer.desk,kantor Ponero
black.fee.pay,Zapłać opłatę za wystawienie
1 # Probably Decentralized localization table: Polish (pl)
762 bpay.h
763 bpay.qty
764 bpay.total
bpay.coin
765 bpay.need
766 bpay.invoice
767 bpay.swap.h
949 explorer.day
950 explorer.pool
951 explorer.desk
952 black.fee.pay
@@ -762,7 +762,6 @@ ponzi.early,Схемы Понци можно запускать со дня {0}.
bpay.h,Оплата
bpay.qty,Количество
bpay.total,Итого (кредиты): {0}
bpay.coin,Монета оплаты (принимает продавец)
bpay.need,К оплате: {0} {1} баланс кошелька: {2}
bpay.invoice,Создать счёт
bpay.swap.h,Автообмен на {0}
@@ -950,3 +949,4 @@ explorer.col.day,День
explorer.day,День {0}
explorer.pool,пул RatDigg
explorer.desk,обменник Ponero
black.fee.pay,Оплата комиссии за размещение
1 # Probably Decentralized localization table: Russian (ru)
762 bpay.h
763 bpay.qty
764 bpay.total
bpay.coin
765 bpay.need
766 bpay.invoice
767 bpay.swap.h
949 explorer.day
950 explorer.pool
951 explorer.desk
952 black.fee.pay
@@ -761,7 +761,6 @@ ponzi.early,第 {0} 天起可发行高息理财。
bpay.h,付款
bpay.qty,数量
bpay.total,合计 {0} 信用点等值
bpay.coin,付款币种(商家收的币)
bpay.need,"需付 {0} {1} 钱包余额 {2}"
bpay.invoice,生成账单
bpay.swap.h,"自动换币为 {0}"
@@ -949,3 +948,4 @@ explorer.col.day,天
explorer.day,第 {0} 天
explorer.pool,RatDigg 矿池
explorer.desk,Ponero 兑换处
black.fee.pay,支付平台费
1 # Probably Decentralized 本地化表:简体中文(zh)
761 bpay.h
762 bpay.qty
763 bpay.total
bpay.coin
764 bpay.need
765 bpay.invoice
766 bpay.swap.h
948 explorer.day
949 explorer.pool
950 explorer.desk
951 black.fee.pay
+13 -2
View File
@@ -184,9 +184,17 @@ namespace Decentralized
}
/// <summary>应用整套 PLEDGER 皮肤:机身、边框、墨水屏、刻字、文字颜色、触控键、滚动条与数据表行。</summary>
public static void Apply(CustomUIWindow win, RectTransform screen, Image bezel, Image paper, ICollection<GameObject> picked, ICollection<Image> clear, IEnumerable<RowDef> rows = null, float fontScale = 1f)
public static void Apply(CustomUIWindow win, RectTransform screen, Image bezel, Image paper, ICollection<GameObject> picked, ICollection<Image> clear, IEnumerable<RowDef> rows = null, float fontScale = 1f, bool frame = true)
{
if (win?.root == null) return;
if (frame) ApplyFrame(win, bezel, paper);
if (screen == null) return;
ApplyScreen(screen, picked, clear, rows, fontScale);
}
/// <summary>窗口外壳:机身、黑边、纸面、标题栏刻字。只在窗口新建时做一次。</summary>
private static void ApplyFrame(CustomUIWindow win, Image bezel, Image paper)
{
Slice(win.root.GetComponent<Image>(), "ui_hw_shell", 10);
if (bezel != null) Slice(bezel, "ui_hw_bezel", 5);
if (paper != null) Slice(paper, "ui_hw_paper", 3);
@@ -208,8 +216,11 @@ namespace Decentralized
}
var content = win.frame?.contentRoot?.GetComponent<VerticalLayoutGroup>();
if (content != null) content.childAlignment = TextAnchor.UpperCenter;
}
if (screen == null) return;
/// <summary>屏幕内的样式:文字、输入框、分隔线、按钮、滚动条、表格行。内容刷新时只对新建的这块调用。</summary>
private static void ApplyScreen(RectTransform screen, ICollection<GameObject> picked, ICollection<Image> clear, IEnumerable<RowDef> rows, float fontScale)
{
if (fontScale > 1.001f)
foreach (var t in screen.GetComponentsInChildren<TextMeshProUGUI>(true))
{
+98 -16
View File
@@ -39,19 +39,42 @@ namespace Decentralized
private static readonly List<Image> _clear = new List<Image>();
private static readonly List<PledgerSkin.RowDef> _rows = new List<PledgerSkin.RowDef>();
// 窗口建好之后保留:之后的刷新只重建页签栏、滚动内容和消息行,不重建窗口框架,滚动位置也不丢。
private static CustomUIWindow _win;
private static RectTransform _screen, _topRoot, _bodyRoot, _noteRoot;
private static ScrollRect _scroll;
private static float _builtW, _builtH;
private static string _scrollKey;
private static bool _dirty;
private static bool Alive() =>
CustomUIManager.Instance != null && CustomUIManager.Instance.IsOpen(Id) && _win != null && _win.root != null
&& _screen != null && _topRoot != null && _bodyRoot != null && _noteRoot != null
&& Math.Abs(_builtW - WinW) < 0.5f && Math.Abs(_builtH - WinH) < 0.5f;
/// <summary>打开或刷新终端。窗口还没开(或窗口大小变了)时马上完整构建;已经开着就只标记要刷新,同一帧里的多次刷新合并成一次(见 <see cref="Flush"/>)。</summary>
public static void Open()
{
if (Session.Data == null) return;
var b = CustomUIManager.Window(Id, L.T("term.title"));
if (b == null) return;
_picked.Clear(); _clear.Clear(); _rows.Clear();
b.SetSize(WinW, WinH).SetDraggable(true).SetCloseOnEscape(true).UseMachineryStyle();
// 黑色外边框包裹墨水屏
b.BeginPanel(ScreenW + Bezel * 2, ScreenH + Bezel * 2, TextAnchor.MiddleCenter, Bezel + 3f, 0f);
var bezel = b.Last.image;
b.BeginPanel(ScreenW, ScreenH, TextAnchor.UpperLeft, 12f, 4f);
var screen = b.CurrentContainer;
var paper = b.Last.image;
if (!Alive()) { OpenFull(); return; }
_dirty = true;
WalletDriver.Ensure();
}
/// <summary>每帧由常驻驱动调用:有待刷新的就重建一次内容区。</summary>
public static void Flush()
{
if (!_dirty) return;
_dirty = false;
if (Session.Data == null || CustomUIManager.Instance == null || !CustomUIManager.Instance.IsOpen(Id)) return;
if (!Alive()) { OpenFull(); return; }
Rebuild();
}
private static string ScrollKey() => string.Join("|", _page, _web3Tab, _grayTab, _blackTab, _sellView, _walletTab, _poinTab);
private static void BuildTop(CustomUIBuilder b)
{
if (_page == Page.Gray && !GrayAvailable) _page = Page.Web3;
TabRows(b, Enum.GetValues(typeof(Page)).Cast<Page>().Where(p => p != Page.Gray || GrayAvailable).Select(p =>
{
@@ -59,9 +82,10 @@ namespace Decentralized
return new TabDef { Name = L.T("tab." + p.ToString().ToLowerInvariant()), On = page == _page, Click = () => { _page = page; _message = null; Open(); } };
}).ToList(), true);
ConnectPicker(b);
b.AddSeparator();
b.BeginScroll(ScreenH - 52f);
_clear.Add(b.Last.image);
}
private static void BuildBody(CustomUIBuilder b)
{
if ((_page == Page.Web3 || _page == Page.Gray) && WalletWindow.Pending != null && !WalletWindow.Pending.Contract) PayPage(b);
else switch (_page)
{
@@ -74,15 +98,74 @@ namespace Decentralized
case Page.Wallets: WalletsPage(b); break;
default: break;
}
b.End();
}
private static void BuildNote(CustomUIBuilder b)
{
if (!string.IsNullOrEmpty(_message)) b.AddLabel(_message, "term_note");
}
/// <summary>完整构建:窗口、黑边、屏幕、页签栏、滚动区、消息行。</summary>
private static void OpenFull()
{
var b = CustomUIManager.Window(Id, L.T("term.title"));
if (b == null) return;
_picked.Clear(); _clear.Clear(); _rows.Clear();
b.SetSize(WinW, WinH).SetDraggable(true).SetCloseOnEscape(true).UseMachineryStyle();
// 黑色外边框包裹墨水屏
b.BeginPanel(ScreenW + Bezel * 2, ScreenH + Bezel * 2, TextAnchor.MiddleCenter, Bezel + 3f, 0f);
var bezel = b.Last.image;
b.BeginPanel(ScreenW, ScreenH, TextAnchor.UpperLeft, 12f, 4f);
var screen = b.CurrentContainer;
var paper = b.Last.image;
b.BeginPanel(ScreenW - 24f, -1f, TextAnchor.UpperLeft, 0f, 4f);
_clear.Add(b.Last.image);
var top = b.CurrentContainer;
BuildTop(b);
b.End();
b.AddSeparator();
b.BeginScroll(ScreenH - 52f);
_clear.Add(b.Last.image);
var body = b.CurrentContainer;
BuildBody(b);
b.End();
b.BeginPanel(ScreenW - 24f, -1f, TextAnchor.UpperLeft, 0f, 0f);
_clear.Add(b.Last.image);
var note = b.CurrentContainer;
BuildNote(b);
b.End();
b.End();
b.End();
var win = b.Show();
_win = win; _screen = screen; _topRoot = top; _bodyRoot = body; _noteRoot = note;
_scroll = body != null ? body.GetComponentInParent<ScrollRect>() : null;
_builtW = WinW; _builtH = WinH; _scrollKey = ScrollKey(); _dirty = false;
Log.Guard("交易终端外观", () => PledgerSkin.Apply(win, screen, bezel, paper, _picked, _clear, _rows, F));
Log.Guard("购物车按钮", () => CartFab(win));
}
/// <summary>只重建页签栏、滚动内容和消息行;窗口框架和滚动视图保留(滚动位置自然不变,换页或换子页签时回到顶部)。</summary>
private static void Rebuild()
{
var m = CustomUIManager.Instance;
_picked.Clear(); _clear.Clear(); _rows.Clear();
CustomUIBuilder.ClearContainer(_topRoot);
CustomUIBuilder.ClearContainer(_bodyRoot);
CustomUIBuilder.ClearContainer(_noteRoot);
BuildTop(new CustomUIBuilder(m, _win, _topRoot));
BuildBody(new CustomUIBuilder(m, _win, _bodyRoot));
BuildNote(new CustomUIBuilder(m, _win, _noteRoot));
string key = ScrollKey();
if (key != _scrollKey)
{
_scrollKey = key;
if (_scroll != null && _scroll.content != null) { var cp = _scroll.content.anchoredPosition; _scroll.content.anchoredPosition = new Vector2(cp.x, 0f); }
}
CustomUIBuilder.RebuildLayout(_topRoot); CustomUIBuilder.RebuildLayout(_bodyRoot); CustomUIBuilder.RebuildLayout(_noteRoot);
Log.Guard("交易终端外观", () => PledgerSkin.Apply(_win, _screen, null, null, _picked, _clear, _rows, F, false));
Log.Guard("购物车按钮", () => CartFab(_win));
}
private static void Go(Page p) { _page = p; _message = null; Open(); }
/// <summary>钱包那边交易落地后刷新终端(开着的话),带上结果消息。</summary>
@@ -1762,8 +1845,7 @@ namespace Decentralized
l.AddLabel(L.T("black.fee.total", Fmt.Credits(fee)), "cart_total");
}, r =>
{
r.AddHeader(L.T("bpay.h"));
r.AddLabel(L.T("bpay.coin"), "bpay_coin_dim");
r.AddHeader(L.T("black.fee.pay"));
r.BeginRow(4f);
foreach (var a in acc) { string asset = a; PledgerSkin.Pick(r, asset, asset == _feeCoin, () => { _feeCoin = asset; Open(); }, _picked); }
r.End();
+10 -2
View File
@@ -97,6 +97,13 @@ namespace Decentralized
return L.T("hw.wallet.n", w.Name ?? (i + 1).ToString());
}
/// <summary>按住 ✓ 签名要多久:基础秒数 × 该钱包当前 Gas 档位的速度倍数(快档短、慢档长)。</summary>
internal static float HoldSecs(string address)
{
var w = Session.Data?.Own(address);
return (float)(Tuning.TxHoldSecs * (w == null ? 1 : TxRules.TierSpeed(Dev(w).Tier)));
}
private static Device Dev(Wallet w)
{
if (!Devices.TryGetValue(w.Address, out var dev)) Devices[w.Address] = dev = new Device { Address = w.Address };
@@ -614,16 +621,17 @@ namespace Decentralized
}
private void Update() { Log.Guard("钱包动画", WalletWindow.Tick); Log.Guard("出金动画", Funds.Tick); }
private void LateUpdate() => Log.Guard("终端刷新", TerminalWindow.Flush);
}
/// <summary>✓ 键上的按住计时:按满 1.2 秒签名,鼠标挪开或松手就重来。进度用游戏自带的按住圆环显示。</summary>
public sealed class HoldToSign : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler
{
private const float Seconds = 1.2f;
private float Seconds = (float)Tuning.TxHoldSecs;
private float held = -1f;
public string Device;
public void OnPointerDown(PointerEventData e) => held = 0f;
public void OnPointerDown(PointerEventData e) { Seconds = WalletWindow.HoldSecs(Device); held = 0f; }
public void OnPointerUp(PointerEventData e) => Stop();
public void OnPointerExit(PointerEventData e) => Stop();