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();