From f5beeea9007a5c9dbe54a3273ca8811445f5d8d1 Mon Sep 17 00:00:00 2001 From: ZHU MINCHAO <48154958+MinchaoZhu@users.noreply.github.com> Date: Thu, 5 Nov 2026 21:57:15 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=88=E7=AB=AF=E5=8F=AA=E9=87=8D=E5=BB=BA?= =?UTF-8?q?=E5=86=85=E5=AE=B9=E5=8C=BA=E5=B9=B6=E5=90=88=E5=B9=B6=E5=90=8C?= =?UTF-8?q?=E5=B8=A7=E5=88=B7=E6=96=B0=EF=BC=9B=E5=B9=B3=E5=8F=B0=E8=B4=B9?= =?UTF-8?q?=E9=A1=B5=E6=96=87=E6=A1=88=EF=BC=9B=E6=8C=89=E4=BD=8F=E7=AD=BE?= =?UTF-8?q?=E5=90=8D=E9=9A=8F=20Gas=20=E6=A1=A3=E4=BD=8D=E7=BC=A9=E7=9F=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- CHANGELOG.md | 6 + src/Decentralized.Domain/Tuning.cs | 2 + src/Decentralized.Domain/TuningTable.cs | 1 + .../ModFiles/Localization/de.csv | 2 +- .../ModFiles/Localization/en.csv | 2 +- .../ModFiles/Localization/es.csv | 2 +- .../ModFiles/Localization/fr.csv | 2 +- .../ModFiles/Localization/ja.csv | 2 +- .../ModFiles/Localization/pl.csv | 2 +- .../ModFiles/Localization/ru.csv | 2 +- .../ModFiles/Localization/zh.csv | 2 +- src/Decentralized/PledgerSkin.cs | 15 ++- src/Decentralized/TerminalWindow.cs | 114 +++++++++++++++--- src/Decentralized/WalletWindow.cs | 12 +- 14 files changed, 138 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1694e87..89cbd82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 未发布 + +- 终端刷新只重建页签栏、滚动内容和消息行,窗口框架和滚动视图保留:滚动位置不再回到顶部(换页或换子页签时才回顶);同一帧里的多次刷新合并成一次。 +- 货架付平台费页:标题“支付平台费”,去掉“付款币种”字样。 +- 按住 ✓ 签名的时间随 Gas 档位变化:快档 0.6 秒、普通档 1.2 秒、慢档 1.8 秒(`Tuning.TxHoldSecs` × 档位速度倍数)。 + ## 1.0.0-rc8 - 灰网商店卖货重构:卖货默认是已上架的橱窗(同一商品聚合成一张卡,同一商品倍率相同);“上架更多”进备货页,左边选标价倍率,货架卡片显示聚合库存,用 − / + 调整本次要上架的数量;右下角“货架 N”进付费页,在清单里核对、选币付上架费后才上架。橱窗里每点一次“下架”预备 +1,右下角“确定下架 N”确认,货回储藏区,上架费不退。上架上限改为同时最多 6 种、每种最多 5 件(原来总共 10 件);倍率表不再显示成交天数。 diff --git a/src/Decentralized.Domain/Tuning.cs b/src/Decentralized.Domain/Tuning.cs index 8e35e5c..80a22b8 100644 --- a/src/Decentralized.Domain/Tuning.cs +++ b/src/Decentralized.Domain/Tuning.cs @@ -182,6 +182,8 @@ namespace Decentralized.Domain public const double TxFeeSlow = 0.5, TxFeeNormal = 1.5, TxFeeFast = 4, TxCongestedFeeMult = 4; /// Gas 档位的确认速度倍数(时间乘它):Gas 越高确认越快、进度条走得越快;Poinbase 出金固定普通档。 public const double TxSpeedSlow = 1.5, TxSpeedNormal = 1, TxSpeedFast = 0.5; + /// PLEDGER 按住 ✓ 签名的基础秒数(普通档),乘档位速度倍数:快档更短、慢档更长。 + public const double TxHoldSecs = 1.2; /// Gas 价格指数:以 GasPeriod 天为周期正弦涨跌,振幅 GasAmp(0.5×–1.5×),每天再乘 1 ± GasNoise 的随机波动。 public const int TxGasPeriod = 7; public const double TxGasAmp = 0.5, TxGasNoise = 0.15; diff --git a/src/Decentralized.Domain/TuningTable.cs b/src/Decentralized.Domain/TuningTable.cs index 093d874..5c7a1b4 100644 --- a/src/Decentralized.Domain/TuningTable.cs +++ b/src/Decentralized.Domain/TuningTable.cs @@ -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, diff --git a/src/Decentralized/ModFiles/Localization/de.csv b/src/Decentralized/ModFiles/Localization/de.csv index 1b9b094..105957c 100644 --- a/src/Decentralized/ModFiles/Localization/de.csv +++ b/src/Decentralized/ModFiles/Localization/de.csv @@ -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 diff --git a/src/Decentralized/ModFiles/Localization/en.csv b/src/Decentralized/ModFiles/Localization/en.csv index d406137..dd882f3 100644 --- a/src/Decentralized/ModFiles/Localization/en.csv +++ b/src/Decentralized/ModFiles/Localization/en.csv @@ -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 diff --git a/src/Decentralized/ModFiles/Localization/es.csv b/src/Decentralized/ModFiles/Localization/es.csv index 9793188..2c2a52e 100644 --- a/src/Decentralized/ModFiles/Localization/es.csv +++ b/src/Decentralized/ModFiles/Localization/es.csv @@ -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 diff --git a/src/Decentralized/ModFiles/Localization/fr.csv b/src/Decentralized/ModFiles/Localization/fr.csv index 7dd25c3..2bee12f 100644 --- a/src/Decentralized/ModFiles/Localization/fr.csv +++ b/src/Decentralized/ModFiles/Localization/fr.csv @@ -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 diff --git a/src/Decentralized/ModFiles/Localization/ja.csv b/src/Decentralized/ModFiles/Localization/ja.csv index d58f903..ed6a564 100644 --- a/src/Decentralized/ModFiles/Localization/ja.csv +++ b/src/Decentralized/ModFiles/Localization/ja.csv @@ -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,出品手数料を支払う diff --git a/src/Decentralized/ModFiles/Localization/pl.csv b/src/Decentralized/ModFiles/Localization/pl.csv index e9bba9e..2f56130 100644 --- a/src/Decentralized/ModFiles/Localization/pl.csv +++ b/src/Decentralized/ModFiles/Localization/pl.csv @@ -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 diff --git a/src/Decentralized/ModFiles/Localization/ru.csv b/src/Decentralized/ModFiles/Localization/ru.csv index 1b894c2..b152590 100644 --- a/src/Decentralized/ModFiles/Localization/ru.csv +++ b/src/Decentralized/ModFiles/Localization/ru.csv @@ -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,Оплата комиссии за размещение diff --git a/src/Decentralized/ModFiles/Localization/zh.csv b/src/Decentralized/ModFiles/Localization/zh.csv index 8b1060a..c7eab39 100644 --- a/src/Decentralized/ModFiles/Localization/zh.csv +++ b/src/Decentralized/ModFiles/Localization/zh.csv @@ -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,支付平台费 diff --git a/src/Decentralized/PledgerSkin.cs b/src/Decentralized/PledgerSkin.cs index 8c60eec..3a57ddc 100644 --- a/src/Decentralized/PledgerSkin.cs +++ b/src/Decentralized/PledgerSkin.cs @@ -184,9 +184,17 @@ namespace Decentralized } /// 应用整套 PLEDGER 皮肤:机身、边框、墨水屏、刻字、文字颜色、触控键、滚动条与数据表行。 - public static void Apply(CustomUIWindow win, RectTransform screen, Image bezel, Image paper, ICollection picked, ICollection clear, IEnumerable rows = null, float fontScale = 1f) + public static void Apply(CustomUIWindow win, RectTransform screen, Image bezel, Image paper, ICollection picked, ICollection clear, IEnumerable 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); + } + + /// 窗口外壳:机身、黑边、纸面、标题栏刻字。只在窗口新建时做一次。 + private static void ApplyFrame(CustomUIWindow win, Image bezel, Image paper) + { Slice(win.root.GetComponent(), "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(); if (content != null) content.childAlignment = TextAnchor.UpperCenter; + } - if (screen == null) return; + /// 屏幕内的样式:文字、输入框、分隔线、按钮、滚动条、表格行。内容刷新时只对新建的这块调用。 + private static void ApplyScreen(RectTransform screen, ICollection picked, ICollection clear, IEnumerable rows, float fontScale) + { if (fontScale > 1.001f) foreach (var t in screen.GetComponentsInChildren(true)) { diff --git a/src/Decentralized/TerminalWindow.cs b/src/Decentralized/TerminalWindow.cs index 13f1bf7..9061a6c 100644 --- a/src/Decentralized/TerminalWindow.cs +++ b/src/Decentralized/TerminalWindow.cs @@ -39,19 +39,42 @@ namespace Decentralized private static readonly List _clear = new List(); private static readonly List _rows = new List(); + // 窗口建好之后保留:之后的刷新只重建页签栏、滚动内容和消息行,不重建窗口框架,滚动位置也不丢。 + 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; + + /// 打开或刷新终端。窗口还没开(或窗口大小变了)时马上完整构建;已经开着就只标记要刷新,同一帧里的多次刷新合并成一次(见 )。 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(); + } + + /// 每帧由常驻驱动调用:有待刷新的就重建一次内容区。 + 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().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"); + } + + /// 完整构建:窗口、黑边、屏幕、页签栏、滚动区、消息行。 + 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() : 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)); } + /// 只重建页签栏、滚动内容和消息行;窗口框架和滚动视图保留(滚动位置自然不变,换页或换子页签时回到顶部)。 + 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(); } /// 钱包那边交易落地后刷新终端(开着的话),带上结果消息。 @@ -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(); diff --git a/src/Decentralized/WalletWindow.cs b/src/Decentralized/WalletWindow.cs index f8ac765..f3b86f2 100644 --- a/src/Decentralized/WalletWindow.cs +++ b/src/Decentralized/WalletWindow.cs @@ -97,6 +97,13 @@ namespace Decentralized return L.T("hw.wallet.n", w.Name ?? (i + 1).ToString()); } + /// 按住 ✓ 签名要多久:基础秒数 × 该钱包当前 Gas 档位的速度倍数(快档短、慢档长)。 + 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); } /// ✓ 键上的按住计时:按满 1.2 秒签名,鼠标挪开或松手就重来。进度用游戏自带的按住圆环显示。 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();