MooTool Next-Compose 状态守卫接线解析:F20 清空历史确认与 F23 图片库 `*ActionEnabled` 统一化
桌面应用开发工具【免费下载链接】MooToolHandy tool set for developers项目地址https://gitcode.com/gh_mirrors/mo/MooTool点击查看免费下载DIFF-647 是 MooTool 的 Compose Desktop 版本next-compose工作区中一次典型的UI 可用性接线wiring切片把分散在界面上的按钮enabled判断收敛到两个可单测的展示层对象TranslationWiringPresentation与ImageWiringPresentation中。本文将围绕该切片的两个功能项展开——翻译工具的历史清空二次确认按钮F20与图片库全链路操作按钮守卫F23逐一说明每个守卫函数的判定语义、在ImageScreen/TranslationScreen中的接线位置以及配套单测如何锁定这些行为最终给出本切片要求的验证命令与执行结果判定方法。切片定位DIFF-646 的延续与 F23 图片库补齐DIFF-647 的基线是 DIFF-646工作区二者属于同一批“*ActionEnabled统一化”工作的一部分。为理解边界先看两个相邻切片DIFF-646 负责翻译工具的主工具栏、单词本与历史入口按钮translateActionEnabled、copyResultActionEnabled、saveWordFromSourceActionEnabled、单词本删除/应用/重译/保存、clearHistoryActionEnabled并在 TranslationWiringPresentationTest 中新增toolbarWordBookAndHistoryActionEnabled用例DIFF-647不重复646 的内容只补齐两块F20 的清空历史确认对话框主按钮enabled以及 F23 图片库的溢出菜单、库底栏、导入、Base64、水印、重命名对话框等入口的统一守卫接线DIFF-648 则是其后续切片覆盖文本对比工具栏基线为 DIFF-647。从源码结构看这类切片的共同模式是展示层对象提供“判定函数”guard function→ 界面组件在MooButton/MooMenuItem的enabled参数处消费判定函数 → 单测直接覆盖判定函数从而把 UI 行为中“什么时候按钮可点”的规则抽离为可独立验证的纯函数。F20 清空历史确认主按钮与入口按钮共用同一条判定入口按钮与确认对话框的接线在 TranslationScreen.kt 中历史面板右上角的“清空历史”入口按钮这样接线MooButton( container.t(translation.clearHistory), enabled TranslationWiringPresentation.clearHistoryActionEnabled(items.size), onClick { session.clearHistoryConfirm true; onReload() } )点击入口按钮并不会立刻清空而是把session.clearHistoryConfirm置为true随后弹出确认覆盖层MooOverlay。确认对话框内的主按钮prominent true使用同名但带Confirm后缀的判定函数见 TranslationScreen.ktMooButton( container.t(translation.clearHistory), prominent true, enabled TranslationWiringPresentation.clearHistoryConfirmActionEnabled(items.size), onClick { container.translations.clearHistory() session.clearHistoryConfirm false onReload() }, )onClick中真正执行container.translations.clearHistory()清空历史记录并关闭确认层、触发onReload()刷新列表。判定函数实现两个判定函数都集中在 TranslationWiringPresentation.ktfun clearHistoryActionEnabled(historyCount: Int): Boolean historyCount 0 /** 对齐清空历史确认对话框主钮同 [clearHistoryActionEnabled]。 */ fun clearHistoryConfirmActionEnabled(historyCount: Int): Boolean clearHistoryActionEnabled(historyCount)语义非常明确历史条目数大于 0 时入口按钮与确认主按钮同时可用历史为空时二者均禁用。确认按钮复用入口判定而非另写新逻辑保证两处状态始终一致这也是 F20 该切片的代码注释“对齐……”所表达的设计意图。而清空确认的完整交互链路入口按钮 → 确认覆盖层 → 主按钮执行清空在TranslationScreen的if (session.clearHistoryConfirm)分支中可以看到TranslationScreen.kt。F23 图片库六类操作的统一守卫接线F23 把图片库中所有需要“先有输入/选中/空闲”才能操作的动作统一到 ImageWiringPresentation.kt并在 ImageScreen.kt 的多处界面位置消费这些判定。判定函数清单与语义判定函数入参返回值条件适用入口canImport(busy)/importActionEnabled(busy)busy 布尔!busy即引擎空闲才允许导入截图、剪贴板导入、文件导入、Base64 导入工具栏与溢出菜单canProcessSelection(count, busy)/processSelectionActionEnabled(count, busy)选中数、busycount 0 !busy有选中且空闲转 SVG、压缩、水印工具栏与溢出菜单、库底栏导出/删除canActOnCurrent(hasCurrent, busy)/actOnCurrentActionEnabled(...)当前图、busyhasCurrent !busy“保存”按钮、溢出菜单“转 Base64”、库底栏重命名canCopyCurrent(hasCurrent)/copyCurrentActionEnabled(hasCurrent)当前图hasCurrent不依赖 busy复制、工具栏“转 Base64”canExportBase64(text)/exportBase64ActionEnabled(text)Base64 文本框text.isNotBlank()Base64 对话框主按钮导入/导出共用canStartWatermark(text)/startWatermarkActionEnabled(text)水印文本text.isNotBlank()水印对话框“开始处理”按钮renamePromptActionEnabled(name)提示框输入name.isNotBlank()重命名/另存对话框主按钮其中代码中为每个canXxx都提供了带ActionEnabled后缀的别名函数例如importActionEnabled(busy) canImport(busy)别名与判定本体完全等价。从命名模式可以推断这是为了让 UI 接线处使用“某动作是否可用”的语义而内部保留“能否”的能力语义同时保持函数之间一一对应、便于检索与统一测试。关键接线位置ImageScreen.kt主工具栏Column顶部的MooButton行ImageScreen.kt截图、剪贴板、导入、Base64 导入全部使用canImport(session.busy)转 SVG、压缩、水印使用canProcessSelection(processing.size, session.busy)保存使用canActOnCurrent(current ! null, session.busy)复制与转 Base64 使用canCopyCurrent(current ! null)溢出菜单MooMenuImageScreen.kt剪贴板导入与 Base64 导入用importActionEnabled(session.busy)转 SVG/压缩/水印用processSelectionActionEnabled(processing.size, session.busy)转 Base64 用actOnCurrentActionEnabled(current ! null, session.busy)图片库底栏ImageScreen.kt重命名用actOnCurrentActionEnabled(...)导出、删除用processSelectionActionEnabled(processing.size, session.busy)Base64 对话框ImageScreen.kt导入模式的主按钮enabled ImageWiringPresentation.exportBase64ActionEnabled(session.base64Text)点击后经runDecodeDataUrl解码Success时保存入库、Failure时走失败通知水印对话框ImageScreen.kt“开始处理”按钮enabled ImageWiringPresentation.startWatermarkActionEnabled(session.watermarkText)即未输入水印文案时不可开始重命名/另存对话框PromptDialogImageScreen.kt主按钮enabled ImageWiringPresentation.renamePromptActionEnabled(session.promptValue)。其中processing的计算规则定义在 ImageScreen.ktsession.selectedNames.ifEmpty { listOfNotNull(current?.name) }——优先取多选集合未显式多选时回退为当前选中的单张图片。这解释了为何“转 SVG/压缩/水印/导出/删除”等批量动作只需要processing.size就能表达“有无目标图片”。结果包装与错误上报辅助除按钮守卫外ImageWiringPresentation还封装了三类执行辅助同为 F23 接线的一部分sealed interface DecodeOutcome { ... } sealed interface ExportAssetsOutcome { ... } fun runDecodeDataUrl(text: String): DecodeOutcome fun runExportAssets(block: () - Unit): ExportAssetsOutcome fun shouldToastProcessFailure(error: Throwable): BooleanrunDecodeDataUrl内部调用 ImageEngine.decodeDataUrl把异常统一折叠为DecodeOutcome.Success/FailurerunExportAssets用runCatching包装导出闭包避免异常穿透到组合层shouldToastProcessFailure对CancellationException与code cancelled的ImageException返回false用户主动取消不弹错误提示其余错误返回true。ImageException定义于 ImageEngine.kt携带机器可读的code如invalid-base64、invalid-image、cancelled供 UI 精确判断提示策略。翻译展示层与 647 配套的既有守卫与底层引擎本切片虽只新增了clearHistoryConfirmActionEnabled但为了让读者掌握完整的 F20 状态守卫体系647 的确认按钮依赖 646 已建立的语义这里汇总 TranslationWiringPresentation.kt 中与之相关的全部判定判定函数入参语义canRunTranslate(text, translating)/translateActionEnabled文本、是否在途!translating text.isNotBlank() text.length TranslationEngine.MAX_TEXT_UNITScopyResultActionEnabled(target)译文target.isNotEmpty()对齐 Electrondisabled{!target}saveWordFromSourceActionEnabled(source)源文本source.isNotBlank()对齐 Electrondisabled{!source}deleteWordActionEnabled(id)/deleteWordConfirmActionEnabled选中单词 idid.isNotBlank()applyWordActionEnabled(hasSelected)选中态hasSelectedretranslateWordActionEnabled(hasSelected, source)选中态源文本hasSelected source.isNotBlank()saveWordEntryActionEnabled(source)单词输入source.isNotBlank()clearHistoryActionEnabled(count)/clearHistoryConfirmActionEnabled历史条数count 0其中canRunTranslate的“长度上限”常量定义在引擎层 TranslationEngine.ktMAX_TEXT_UNITS 50_000且 translate 在真正发起网络请求前会再次校验超长文本并直接返回INVALID_REQUEST因此 UI 层的长度守卫只是“提前禁点”引擎层仍有兜底。另外buildInput中timeoutWire经 clampTimeout 被钳制到1_000..120_000毫秒区间provider 字符串经parseProvider归一化非bing一律视为Google。单测如何锁定这些守卫TranslationWiringPresentationTestTranslationWiringPresentationTest.kt 中与本切片直接相关的用例是toolbarWordBookAndHistoryActionEnabledassertFalse(TranslationWiringPresentation.clearHistoryActionEnabled(0)) assertTrue(TranslationWiringPresentation.clearHistoryActionEnabled(1)) assertFalse(TranslationWiringPresentation.clearHistoryConfirmActionEnabled(0)) assertTrue(TranslationWiringPresentation.clearHistoryConfirmActionEnabled(2))即历史为空0 条时入口与确认主按钮均禁用非空时均启用。同文件的其他用例还验证了buildInput的 provider 归一化与超时钳制999_999 → 120_000、500 → 1_000、runTranslate超长文本无网络即返回INVALID_REQUEST、runSaveWord的成功/失败包装以及failureMessage优先使用异常消息等行为。ImageWiringPresentationTestImageWiringPresentationTest.kt 覆盖 F23 的核心守卫processRequiresSelectionAndIdlecanProcessSelection(0, false)为假、canProcessSelection(2, busytrue)为假、(1, false)为真并顺带验证importActionEnabled(busytrue)为假、actOnCurrentActionEnabled(true, false)为真、exportBase64ActionEnabled( )空白串为假、startWatermarkActionEnabled(wm)为真、renamePromptActionEnabled()为假runExportAssetsWrapsSuccessAndFailure空闭包返回Success抛IOException返回FailureshouldToastProcessFailureSkipsCancelCancellationException与ImageException(cancelled, )均不弹提示ImageException(missing, )则弹。验证命令与执行环境本切片文档给出的验证方式与相邻切片一致需要在 JDK 21 环境下于next-compose目录执行./gradlew :composeApp:desktopTest --offline --no-daemon该命令运行composeApp模块的桌面端 JVM 单测TranslationWiringPresentationTest与ImageWiringPresentationTest即在此阶段执行--offline表示仅使用 Gradle 本地缓存不访问网络--no-daemon表示本次构建不常驻守护进程CI 或一次性验证场景更可控辅助产物冒烟脚本./scripts/verify-product-evidence-prep.sh该脚本位于 next-compose/scripts/verify-product-evidence-prep.sh是非交互式的产物证据准备冒烟检查依次验证 vault 外部冲突、git merge/rebase 冲突、编辑器 IME、托盘截屏等证据脚本可正常生成预期文件并在 git 缺失时跳过相关分支最后对prepare-p7-package-smoke.sh做bash -n语法检查。它与本次 UI 守卫切片本身不直接相关作用是在提交前确认产品证据准备链路未被破坏。判定标准若desktopTest全部用例通过且verify-product-evidence-prep.sh以all product evidence prep checks passed结尾退出码为 0则 DIFF-647 切片验证通过。小结一条可复用的“守卫接线”工程模式DIFF-647 的价值不仅在于两处具体按钮更在于它示范了一条适用于 MooTool 全工具链的工程模式把 UI 可用性规则收敛为展示层纯函数UI 只负责消费enabled测试只面向纯函数。在此基础上判定逻辑集中在 TranslationWiringPresentation.kt 与 ImageWiringPresentation.kt 两个文件中界面代码零散的业务条件被替换为可读性更强的语义调用每个判定函数都有对应别名与对应测试前后续切片DIFF-646 翻译工具栏/单词本、DIFF-648 文本对比工具栏沿用同一套路保证同类需求的可维护性涉及引擎层时UI 守卫只负责“提前禁点”引擎层如TranslationEngine.translate的长度兜底、ImageEngine.decodeDataUrl的格式校验仍有最终校验形成双层防线。对于后续要接入图片库新入口或新增翻译相关按钮的开发者正确做法是先在对应*WiringPresentation中新增canXxx/xxxActionEnabled判定函数再在*Screen中把按钮enabled接到该函数最后在*WiringPresentationTest中补充断言——这正是 DIFF-647 全切片展示的标准流程。赞分享桌面应用开发工具【免费下载链接】MooToolHandy tool set for developers项目地址https://gitcode.com/gh_mirrors/mo/MooTool点击查看免费下载相关推荐MooTool next-compose配置转换工具的 *ActionEnabled 守卫接线与 tools.exportDirectory 统一导出链MooTool next compose配置转换工具的 ActionEnabled 守卫接线与 tools.exportDirectory 统一导出链 本篇基桌面应用开发工具MooTool next-compose 随机串 Tab 的 ActionEnabled 守卫设计DIFF-665 切片解析MooTool next compose 随机串 Tab 的 ActionEnabled 守卫设计DIFF 665 切片解析 本篇聚焦 MooTool 的 C桌面应用开发工具MooTool next-composeF07 Protobuf 工具栏 *ActionEnabled 守卫与 ProtobufScreen 接线实现DIFF-655MooTool next composeF07 Protobuf 工具栏 ActionEnabled 守卫与 ProtobufScreen 接线实现DIFF桌面应用开发工具上一篇Telegraf sensors 输入插件基于 lm-sensors 采集硬件温度、电压与功耗指标的完整指南下一篇3分钟搞定抖音内容收集这个开源工具让你告别手动下载烦恼创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

m3u8 与 mpd 流媒体下载完整指南:N_m3u8DL-RE 三类任务一次跑通,报错排查不再靠猜

m3u8 与 mpd 流媒体下载完整指南:N_m3u8DL-RE 三类任务一次跑通,报错排查不再靠猜

m3u8 与 mpd 流媒体下载完整指南:N_m3u8DL-RE 三类任务一次跑通,报错排查不再靠猜 【免费下载链接】N_m3u8DL-RE Cross-Platform, modern and powerful stream downloader for MPD/M3U8/ISM. English/简体中文/繁體中文. 项目地址: https://gitcode.c…

2026/10/16 1:36:41 阅读更多 →
四轮全向底盘工训纪实

四轮全向底盘工训纪实

四轮全向底盘工训纪实1 工程训练纪实前言2 组装过程2.1 结构说明2.2 具体步骤3 调整电控3.1 伺服电机初始化3.2 步进电机控制3.2.1 抬笔与落笔3.2.2 修改绘图范围3.2.3 控制全向底盘移动1 工程训练纪实前言 这是南京理工大学暑期工程训练(金工实习)机器…

2026/10/16 1:36:41 阅读更多 →
WuKongIM pkg/ 三层架构重构实战:从 15 个散落包到 Controller / Group(Slot) / Channel 分层实施指南

WuKongIM pkg/ 三层架构重构实战:从 15 个散落包到 Controller / Group(Slot) / Channel 分层实施指南

即时通讯后端 【免费下载链接】WuKongIM More than just IM 不只是即时通讯(IM) 项目地址: https://gitcode.com/gh_mirrors/wu/WuKongIM 点击查看 免费下载 本文以 WuKongIM 仓库内的 docs/superpowers/plans/2026-04-10-pkg-restructure-implementation.md 实施计…

2026/10/16 1:36:41 阅读更多 →

最新新闻

微信小程序圆环组件开发:Canvas 2D与CSS方案选型及性能优化实战

微信小程序圆环组件开发:Canvas 2D与CSS方案选型及性能优化实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:13:02 阅读更多 →
interface 的底层原理

interface 的底层原理

深入浅出 Go 语言:Interface 的底层实现原理在 Go 语言中,接口(interface)是实现多态和解耦的核心机制。与其他面向对象语言不同,Go 采用的是“隐式实现”(Duck Typing,鸭子类型)——…

2026/10/16 3:13:02 阅读更多 →
【C++入门】编译链接模型 - 08 静态库为什么像一包目标文件

【C++入门】编译链接模型 - 08 静态库为什么像一包目标文件

博主介绍:程序喵大人 35 - 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章,首发gzh,见文末👇&#x…

2026/10/16 3:13:02 阅读更多 →
重复测量数据全攻略:2026 一篇讲透论文重复测量实验设计,把变量控制与记录规范讲清

重复测量数据全攻略:2026 一篇讲透论文重复测量实验设计,把变量控制与记录规范讲清

同一批被试在四个时间点各测一次,交到导师手里却被追问「你的实验设计写在哪」。重复测量方差分析、线性混合模型这些名称不难写,难的是交代清楚每次观测为何落在这个时点、谁在中途退出、缺失值依据什么规则处置。下文从自变量控制、测量间隔、批次安排…

2026/10/16 3:13:02 阅读更多 →
信贷风控用户画像实战:从标签体系到贷前贷中贷后策略落地

信贷风控用户画像实战:从标签体系到贷前贷中贷后策略落地

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:13:02 阅读更多 →
Java字符串转数字的正确方法

Java字符串转数字的正确方法

java中把字符串转成 的方法更新时间为二零二三年七月七日零九点四十分零三秒, 作者是。在Java环境里头, 大家可以利用某个类里面的那个叫作静态的方法, 把一段写着数字的字符串变成对应那种类型的数, 这篇文章会配上一些具体的代码例子, 来把这个事情从字符串弄成具体数值的过程…

2026/10/16 3:12:01 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →