From f2a948f059fc5119f3c47acabb530b2e411addc5 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Sun, 6 Sep 2026 00:45:44 +0800 Subject: [PATCH] fix(ui): keep diagnostic stop clear of Logo skip --- .../LocalPlatformLogin.ts | 6 ++-- .../local-platform-login/local-login-view.ts | 25 ++++++++++++++++ .../local-platform-login/view.test.ts | 29 ++++++++++++++++++- .../2026-09-06-logo-countdown-acceptance.md | 20 +++++++++++-- 4 files changed, 74 insertions(+), 6 deletions(-) diff --git a/cocoscreator_projects/YouleNexus/assets/scripts/local-platform-login/LocalPlatformLogin.ts b/cocoscreator_projects/YouleNexus/assets/scripts/local-platform-login/LocalPlatformLogin.ts index 31d926b..ba09187 100644 --- a/cocoscreator_projects/YouleNexus/assets/scripts/local-platform-login/LocalPlatformLogin.ts +++ b/cocoscreator_projects/YouleNexus/assets/scripts/local-platform-login/LocalPlatformLogin.ts @@ -6,7 +6,7 @@ import type { NativeHost } from '../../framework/config/sources/native-settings. import type { PageModel } from '../../framework/presentation/ui-contracts.ts'; import { createLocalLoginHost, type LocalLoginHost } from './local-login-host.ts'; import type { LocalLoginEvidence } from './local-login-transport.ts'; -import { CocosLocalLoginView, CocosLogoCountdownView, createLogoCountdown, createAssetLoadTask, createCocosFrameScheduler, requireNode } from './local-login-view.ts'; +import { CocosLocalLoginView, CocosLogoCountdownView, createLogoCountdown, createAssetLoadTask, createCocosFrameScheduler, positionDiagnosticStopButtonBelow, requireNode } from './local-login-view.ts'; const { ccclass, property } = _decorator; @@ -57,7 +57,9 @@ export class LocalPlatformLogin extends Component { requireNode(logo, 'group-32').active = false; const countdownLabels = logo.getComponentsInChildren(Label).filter(label => label.node.name === 'Spirit3104'); if (countdownLabels.length !== 1) throw new Error('Logo requires exactly one Spirit3104 Label'); - this.countdownView = new CocosLogoCountdownView(requireNode(logo, 'group-1/Spirit3103'), countdownLabels[0].node, + const logoButton = requireNode(logo, 'group-1/Spirit3103'); + positionDiagnosticStopButtonBelow(stopButton, logoButton); + this.countdownView = new CocosLogoCountdownView(logoButton, countdownLabels[0].node, () => this.countdown?.skip()); this.countdown = createLogoCountdown({ now: () => performance.now(), schedule: (callback, ms) => { diff --git a/cocoscreator_projects/YouleNexus/assets/scripts/local-platform-login/local-login-view.ts b/cocoscreator_projects/YouleNexus/assets/scripts/local-platform-login/local-login-view.ts index 527d856..9486a02 100644 --- a/cocoscreator_projects/YouleNexus/assets/scripts/local-platform-login/local-login-view.ts +++ b/cocoscreator_projects/YouleNexus/assets/scripts/local-platform-login/local-login-view.ts @@ -8,6 +8,31 @@ interface ViewReferences { export interface LogoCountdownState { readonly visible: boolean; readonly text: string; } +const DIAGNOSTIC_STOP_GAP = 12; + +/** Keeps the scene diagnostic control clear of the native Logo click region. */ +export function positionDiagnosticStopButtonBelow(stopButton: Node, logoButton: Node): void { + const stopTransform = stopButton.getComponent(UITransform); + const logoTransform = logoButton.getComponent(UITransform); + const stopParentTransform = stopButton.parent?.getComponent(UITransform); + if (!stopTransform || !logoTransform || !stopParentTransform) { + throw new Error('Diagnostic stop layout requires native UITransform bindings'); + } + const widget = stopButton.getComponent(Widget); + if (widget) { + widget.updateAlignment(); + widget.enabled = false; + } + const logoBottom = logoTransform.convertToWorldSpaceAR( + new Vec3((0.5 - logoTransform.anchorX) * logoTransform.width, -logoTransform.anchorY * logoTransform.height, 0), + ); + const bottomInStopParent = stopParentTransform.convertToNodeSpaceAR(logoBottom); + const current = stopButton.position; + stopButton.setPosition(new Vec3(current.x, + bottomInStopParent.y - DIAGNOSTIC_STOP_GAP - (1 - stopTransform.anchorY) * stopTransform.height, + current.z)); +} + /** Native input and measured label layout, independent of serialized label parentage. */ export class CocosLogoCountdownView { private readonly label: Label; diff --git a/cocoscreator_projects/framework-tests/local-platform-login/view.test.ts b/cocoscreator_projects/framework-tests/local-platform-login/view.test.ts index 680f208..2272c98 100644 --- a/cocoscreator_projects/framework-tests/local-platform-login/view.test.ts +++ b/cocoscreator_projects/framework-tests/local-platform-login/view.test.ts @@ -141,6 +141,30 @@ test('Logo native binding measures label around button center and releases its t button.emit('touch-end'); assert.equal(clicks, 1); view.dispose(); assert.equal(button.listenerCount('touch-end'), 0); assert.equal(button.active, false); }); + +test('diagnostic stop button is placed below Logo across different parent coordinates without changing its right-side x', () => { + const { positionDiagnosticStopButtonBelow } = load(); + assert.equal(typeof positionDiagnosticStopButtonBelow, 'function'); + const logo = new Node('Spirit3103'), logoParent = new Node('logo-parent'); + const stop = new Node('StopButton'), canvas = new Node('Canvas'); + logo.parent = logoParent; stop.parent = canvas; stop.position = new Vec3(665, 310, 7); + const logoTransform = new UITransform(); + Object.assign(logoTransform, { width: 208, height: 59, anchorX: 0.5, anchorY: 0.5 }); + logoTransform.convertToWorldSpaceAR = value => new Vec3(value.x + 671.37, value.y + 311.5, value.z); + const stopTransform = new UITransform(); + Object.assign(stopTransform, { width: 220, height: 64, anchorX: 0.5, anchorY: 0.5 }); + const canvasTransform = new UITransform(); + canvasTransform.convertToNodeSpaceAR = value => new Vec3(value.x - 100, value.y - 40, value.z); + logo.components.set(UITransform, logoTransform); stop.components.set(UITransform, stopTransform); + canvas.components.set(UITransform, canvasTransform); + const widget = new Widget(); stop.components.set(Widget, widget); + + positionDiagnosticStopButtonBelow(stop, logo); + + assert.equal(widget.enabled, false, 'runtime position must not be overwritten by the native Widget'); + assert.equal(stop.position.x, 665); assert.equal(stop.position.z, 7); + assert.equal(stop.position.y, 198, 'button top is 12 px below the logo bottom in Canvas coordinates'); +}); function fixture() { const refs = { loadingRoot: new Node(), loginRoot: new Node(), resultRoot: new Node(), statusOverlay: new Node(), statusLabel: new Label(), resultLabel: new Label() }; @@ -321,7 +345,10 @@ test('minimum display ignores an early timer wake and cancellation clears its re } }); async function started(emitDraw = true) { const component = new exports.LocalPlatformLogin(); const f = fixture(); - Object.assign(component, f.refs, { stopButton: new Node(), loadingPrefab: {}, loginPrefab: {} }); + const stopButton = new Node('StopButton'), canvas = new Node('Canvas'); + stopButton.parent = canvas; stopButton.components.set(UITransform, new UITransform()); + canvas.components.set(UITransform, new UITransform()); + Object.assign(component, f.refs, { stopButton, loadingPrefab: {}, loginPrefab: {} }); const logo = new Node('Layer1_Logo'); const group = new Node('group-1'); const bar = new Node('Spirit254'); bar.components.set(ProgressBar, new ProgressBar()); const button = new Node('Spirit3103'), text = new Node('Spirit3104'); diff --git a/docs/superpowers/reports/2026-09-06-logo-countdown-acceptance.md b/docs/superpowers/reports/2026-09-06-logo-countdown-acceptance.md index 8c72d72..e520f69 100644 --- a/docs/superpowers/reports/2026-09-06-logo-countdown-acceptance.md +++ b/docs/superpowers/reports/2026-09-06-logo-countdown-acceptance.md @@ -1,6 +1,6 @@ # Logo 倒计时与跳过验收 -日期:2026-09-06。基线09e80e5,主checkout分支codex/local-platform-login。用户批准恢复Spirit3103/Spirit3104的原工程行为。 +状态:网页补验已完成,含实际鼠标点击与清理。日期:2026-09-06。基线09e80e5,主checkout分支codex/local-platform-login。用户批准恢复Spirit3103/Spirit3104的原工程行为。 ## 原工程依据与实现边界 @@ -19,11 +19,25 @@ - 五个既有TS经MCP刷新,编辑器主checkout/currentLocalPlatformLogin,无资源写入。创建独立sandbox Chromium窗口12(fp_ad50e68505262f18),未点击登录。 - 实际无参数网页fp_ce914709f5aedc1e:ready=true、stopped=false、pending=0、资源progress=1。3104父节点为Spirit3103,文字倒计时1s但控件已隐藏。firstDraw1078.7ms、展示门结束1239.5ms、资源就绪1248ms、登录页1249.4ms;配置默认短等待未绕过资源门。无component-failure。 - 长倒计时视觉夹具尝试仅在独立窗口内装饰HttpConfigFetcher返回数据并重载同一场景,未写生产配置,未记录成功结果。该MCP调用没有返回,后续只读编辑器查询也挂起;已停止工具等待。HTTP8765/health仍返回ok,不能据此认定编辑器调用可用。已请求用户关闭独立验证窗口/恢复Funplay扩展。 -- 待恢复MCP后完成:长倒计时文字逐秒变化、实际点击跳过与到期隐藏的网页验收;恢复临时fetcher装饰(若安装成功)并停止/关闭独立窗口。此项未完成,不以50项模拟测试冒充网页验收。 +- 首次验收时待恢复MCP后完成(已由下方补验完成):长倒计时文字逐秒变化、实际点击跳过与到期隐藏的网页验收;恢复临时fetcher装饰(若安装成功)并停止/关闭独立窗口。当时未完成,未以50项模拟测试冒充网页验收。 ## 用户资源改动保护 实施期间只读检查发现Logo.prefab新增未提交差异:Spirit3104已移为Spirit3103子节点,局部位置为0。该差异不是本批工具产生,单独记录SHA256并保留,不随代码提交。代码应唯一定位目标Label并按实际父节点布局,避免绑定旧的同级路径;支持这一现有用户布局不需要修改序列化资源。 -整体独立代码审查通过,无可操作问题;结论附带上述网页长倒计时验收未完成的限定。原有50个未跟踪文件与外部Logo.prefab快照SHA256均不变,两项历史meta删除保留。 +整体独立代码审查通过,无可操作问题;首次审查时附带网页长倒计时待验收的限定,现已完成下列补验。原有50个未跟踪文件与外部Logo.prefab快照SHA256均不变,两项历史meta删除保留。 + +## MCP恢复后的最终补验 + +- MCP恢复,旧窗口12已关闭;新独立窗口13,主checkout和Creator3.8.8不变。避免再次重载场景,使用当前实际编译LocalPlatformLogin类创建临时运行时实例,复用场景引用。只在该浏览器内装饰fetcher返回内存配置,验证有效launchWaitTime等于夹具指定值;不改发布配置、资源、远程服务或持久化数据。 +- 实际默认配置仍为10ms,正常页面ready=true、无错误(fp_e983ffe0d6c28f91);修复后再次正常启动通过(fp_cf9a986deb3363ee)。 +- 15秒夹具:文字从倒计时15s 跳过变为倒计时14s 跳过;资源progress=1但ready=false,Label在父背景中心(fp_aab5629e8b3f7d8a)。 +- 实际鼠标验收发现诊断StopButton与3103重叠,点击被停止按钮接收(fp_4e244b818e107608)。修复只在运行时将StopButton放到Logo背景底边下12单位,保持原x/z;应用Widget布局后关闭其运行时覆盖。两处TS与一个测试变更,无序列化资源修改。独立修复复审通过。 +- 修复后实鼠点击屏幕(1467,98):30秒倒计时提前约0.55秒完成展示门并进入login,ready=true、stopped=false、控件隐藏、pending=0(fp_0f0778181f3dc1cb)。截图已检查:两个按钮不再重叠,倒计时文字居中。临时截图temp/mcp-captures/logo-countdown-ready.png未提交。 +- 2.2秒自然到期夹具:ready=false/控件可见变为ready=true/控件隐藏(fp_991219d94f45c3c1)。 +- 暂缓真实资源加载任务完成的夹具:点击后ready=false、stopped=false,显示倒计时10s;释放资源任务后显示倒计时10s 跳过,仍未提前进入login,证明早点击不排队(fp_7a2ec06865f205b3)。 +- 提前停止后文字不变、控件隐藏、ready=false、pending=0(fp_544552041e1a4dce)。诊断StopButton实际鼠标点击仍有效。最终恢复fetcher和临时资源方法,stopped=true、ready=false、pending=0,然后关闭窗口13;编辑器dirty=false(fp_be8fcfffbf985067)。 +- 修复TDD先16通过/1失败,后17/17通过;最终完整显式枚举TS637/637。框架及现代Creator严格类型检查通过;此前指定架构49/49通过,本次未改变架构边界。没有重复生成资源或测试其他RPC。 + +本批启动倒计时、资源完成显示跳过、就绪后跳过、到期隐藏、停止清理网页验收完成。原生广告图片替换、其他平台RPC不在本批范围。 \ No newline at end of file