外观
专注主题开发 预发布版本
更新时间:2025年5月10日
成功导入或创建专注主题项目后,您将在指定的开发文件夹中看到以下标准文件和目录结构。这些构成了专注主题(.dft
文件,本质上是一个ZIP压缩包)的核心内容。
MyFocusTheme/
├── info.json # 主题元数据与配置定义
├── main.html # 主题核心布局与逻辑文件
├── preview.webp # 主题预览图 (通常由Doing自动生成)
├── setting/ # 用户自定义配置的默认值
│ └── settings.json
├── lib/ # 建议存放第三方库文件 (JS, CSS等)
└── assets/ # 建议存放静态资源 (图片, 字体等)
资源引用规则
开发者需要特别注意,为了保证主题的安全性和性能:所有主题内使用的资源(包括图片、字体、脚本、样式表等)必须包含在.dft
文件包内,并通过相对路径引用。严禁从外部网络加载任何资源或访问本地文件系统(Doing平台提供的API除外)。
1 info.json
- 主题信息文件
info.json
文件用于定义专注主题的基本信息、特性以及用户可配置项。
示例 info.json
:
json
{
"id": "zzz66d35-8048-46c8-8627-ac8d89a80ce9",
"sceneRenderVersion": 2,
"version": 20250509,
"name": "标准 Web",
"color": "#FF9C27B0",
"feature": [
"followActionColor",
"darkMode"
],
"setting": []
}
关键字段说明:
id
: 专注主题的唯一标识符。- 发布时: 此ID由Doing系统分配,确保唯一性。
- 开发调试阶段: 开发者可以自行设置一个临时的唯一ID,方便本地测试和管理。
sceneRenderVersion
: 主题渲染引擎的版本号,用于兼容性控制。请保持为2.version
: 专注主题自身的版本号(例如YYYYMMDD
格式的日期,或一个自增数字)。此字段用于主题更新时比较版本新旧。Doing平台会根据此版本号判断是否需要提示用户更新主题。name
: 专注主题在Doing应用中显示的名称。color
: 主题的代表色,通常用于主题列表的预览或作为默认强调色。格式为HEX颜色代码(例如#FF9800
)。feature
: 主题支持的特性列表。例如:followActionColor
: 主题颜色会跟随专注模式主题色变化。darkMode
: 主题能够响应深色模式切换。
setting
: 定义用户可在主题设置界面中自定义的配置项。
2.2 main.html
- 核心布局与逻辑
main.html
是专注主题的入口文件和核心,负责定义计时界面的HTML结构、CSS样式以及JavaScript交互逻辑。
核心职责:
- 界面渲染:构建用户所见的计时界面,包括时间显示、控制按钮、背景、动画效果等。
- 数据展示:通过JavaScript API从Doing应用获取实时数据(如计时器状态、剩余时间、设备信息等)并展示在界面上。
- 用户交互:响应用户的操作(如点击按钮),并通过JavaScript API调用Doing应用的内置功能(如暂停/继续、全屏、打开白噪音等)。
- 动态更新:根据Doing应用的状态变化(如计时器更新、模式切换)动态调整界面显示。
示例结构(概念性):
开发者不必严格按照此示例的结构编写,可以根据自己的设计和技术选型自由组织代码。
关键在于理解如何在 main.html
中与Doing应用进行交互:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>专注主题</title>
<script src="lib/your-lib.js"></script>
<link href="lib/your-styles.css" rel="stylesheet">
<style>
/* 您的内联样式 */
body { /* ... */ }
</style>
</head>
<body>
<div id="timerDisplay"></div>
<button id="pauseButton">暂停</button>
<script>
// 您的JavaScript逻辑
// 1. 获取DOM元素
// 2. 实现 onUpdate() 方法
// 3. 在适当的时候调用 doing.getState() 和 doing.call()
// 4. 监听用户事件并调用 doing.call()
</script>
</body>
</html>
2.2.1 onUpdate()
- 状态更新
这是由Doing应用调用的核心回调函数,开发者必须在 main.html
的JavaScript中实现此函数。当Doing应用内的计时器状态、专注模式、设备信息等发生变化时,onUpdate()
会被自动触发。
您应该在此函数内调用 doing.getState()
获取最新数据,并根据这些数据更新您的HTML界面。
javascript
onUpdate = function() {
const state = doing.getState(); // 获取最新状态数据
if (state) {
// 根据 state 更新您的DOM元素
// 例如: document.getElementById('timerDisplay').textContent = state.timer.currentRemainOrPastTimeStr;
console.log("State updated:", state);
}
};
2.2.2 getState()
- 获取状态
此方法用于从Doing应用获取当前的完整状态信息,包括计时器、设备、用户偏好等。
返回数据结构示例:
doing.getState()
返回一个JSON对象,其结构大致如下(具体字段可能随Doing版本更新而调整,请以实际测试为准):
json
{
"focusMode": { // 当前专注模式的配置信息
"name": "开发模式",
"description": "",
"actionName": "正计时", // 计时类型 (正计时/番茄计时)
"workDuration": -1, // 工作时长 (毫秒, -1表示非番茄计时)
"restDuration": -1, // 休息时长 (毫秒, -1表示非番茄计时)
"repeat": 1, // 重复次数
"color": "#FFFBEBAE" // 此专注模式的主题色
},
"status": { // 当前应用的即时状态
"focusStatus": "work", // "work", "rest", "pause", "finish"
"dnd": "false", // 是否开启勿扰(或静音)模式 ("true" / "false")
"keepScreenOn": "true", // 是否保持屏幕常亮 ("true" / "false")
"fullscreen": "false" // 是否全屏 ("true" / "false")
},
"device": { // 设备相关信息
"platform": "macos", // "android", "ios", "macos", "windows", "web"
"battery": {
"level": 100, // 电量百分比 (0-100)
"status": "full" // "charging", "discharging", "full", "unknown"
},
"time": 1746807753577, // 当前设备时间戳 (毫秒)
"safeArea": { // 屏幕安全区域边距 (px)
"top": 24,
"bottom": 24,
"left": 24,
"right": 24
}
},
"timer": { // 计时器详细数据
"currentRemainOrPastTimeStr": "22 : 02", // 当前剩余/已过时间 (格式化字符串)
"currentRemainOrPastTimeInMillisecond": 1322185, // (毫秒)
"repeatCount": 0, // 当前重复轮次
"currentTotalTimeInMillisecond": 1, // 当前计时段总需时长 (毫秒, 对于正计时为1)
"focusProcess": [ // 专注过程记录,time为该时段开始时间戳
{ "type": "work", "time": 1746806431284, "data": {} },
{ "type": "rest", "time": 1746807753577, "data": {} },
{ "type": "work", "time": 1746807763577, "data": {} }
],
"isFinished": false, // 当前计时是否已完成
"currentTotalFocusTime": 1322294 // 当前累计专注时长 (毫秒)
},
"res": { // Doing应用提供的资源,如每日一句
"motto": "四顾山光接水光,凭栏十里芰荷香。"
},
"preference": { // 用户在Doing全局或部分主题设置中的偏好
"showFocusUpperRightWidgetTodayRemainTime": "true",
"24HourSystem": "true", // 是否使用24小时制
"strictMode": "true", // 是否开启严格模式(仅安卓可能为true)
"strictModeWhiteList":"com.liguse.doing,com.android.phone", // 严格模式白名单(仅安卓)
"showFocusPause":"true", // 是否显示暂停按钮
"autoAODMode":"false", // 是否自动开启AOD模式
"locale":"zh-CN" // 当前语言环境
// ...以及通过本主题info.json中setting定义的用户配置项
}
}
开发者应在 window.onUpdate()
中调用此方法,并根据返回的数据更新界面。
性能提示
onUpdate() 方法会在Doing应用的状态发生变化时被调用,调用非常频繁,因此请确保在此函数内的代码尽可能高效,以避免影响用户体验。如需要首次进入初始化的一次性复杂逻辑,可考虑通过变量标记来控制。
2.2.3 doing.call()
- 调用功能
此方法允许您的专注主题调用Doing的应用功能,与控制专注状态。
调用语法:
javascript
doing.call(argumentsArray);
其中 argumentsArray
是一个包含两个元素的数组:
- 第一个元素 (字符串): 功能类型,目前支持
"action"
或"function"
。 - 第二个元素 (字符串): 具体的功能名称。
可用功能列表:
action
类型 (通常用于状态切换或直接操作):doing.call(["action", "exit"]);
尝试退出专注模式doing.call(["action", "togglePause"]);
切换暂停/继续状态doing.call(["action", "toggleKeepScreenOn"]);
切换屏幕常亮状态doing.call(["action", "toggleDND"]);
切换勿扰(静音)模式状态doing.call(["action", "toggleFullscreen"]);
切换全屏状态doing.call(["action", "rotateScreen"]);
(如支持)旋转屏幕doing.call(["action", "minimizeFocus"]);
最小化专注doing.call(["action", "startDragging"]);
(桌面端) 允许用户通过拖拽主题界面来移动窗口
function
类型 (通常用于打开新界面或执行特定任务):doing.call(["function", "showWhiteNoiseDialog"]);
显示白噪音弹窗doing.call(["function", "showEventDialog"]);
显示日程页面弹窗doing.call(["function", "showInstantRecordDialog"]);
显示记录弹窗doing.call(["function", "showLeftScreen"]);
展示左侧辅助屏幕doing.call(["function", "showRightScreen"]);
展示右侧辅助屏幕
示例:为按钮添加退出功能
html
<button onclick="doing.call(['action', 'exit'])">退出</button>
2.3 preview.webp
- 主题预览图
此图片文件用作专注主题在Doing应用内主题商店或选择列表中的预览图。
- 自动生成:通常情况下,当您在创作者工坊上传或更新主题时,Doing应用会根据您当前主题的运行状态自动截取并生成此
preview.webp
文件。 - 手动替换:如果需要,您也可以在打包
.dft
文件前自行替换此预览图,但请确保图片内容能准确反映主题的实际外观。尺寸需要为520*960的webp格式图片。
2.4 setting/
- 用户配置默认值
setting/
文件夹及其内部的 settings.json
文件用于存储您在 info.json
中定义的、用户可自定义配置项的默认值。
使用流程:
定义配置项 (
info.json
): 您首先需要在info.json
的setting
数组中定义每个配置项的元数据,包括其类型、标题、标识名(preferenceName
)等。例如,在
info.json
中定义一个名为backgroundBlur
的滑块配置项:json// 在 info.json 的 "setting" 数组中 { "type": "SettingItem", // 固定值 "contentType": "seekbar", // 配置项类型: seekbar, switch "data": { // 特定于 contentType 的数据 "max": "10", // seekbar最大值 "min": "0" // seekbar最小值 }, "title": "背景模糊度", // 在设置界面显示的标题 "preferenceName": "backgroundBlur", // 用于在代码中获取此配置值的唯一键名 "icon": "0xf5c9" // (可选) 图标代码 }
提供默认值 (
setting/settings.json
): 然后在setting/settings.json
文件中,为该preferenceName
提供一个初始默认值。示例
setting/settings.json
:json{ "backgroundBlur": "4.3" }
在主题中获取配置值 (
main.html
的 JavaScript): 在您的main.html
脚本中,可以使用doing.getState().preference.xxx
来获取用户对该配置项的当前设定值(如果用户未修改,则获取到的是您设置的默认值)。配置值类型
doing.getPreference()
方法返回的配置值始终为字符串类型。如果您的逻辑需要数值、布尔值或其他类型,请务必在代码中进行显式转换(例如使用parseFloat()
,parseInt()
, 或value === "true"
)。
2.5 lib/
- 库文件夹
这是一个建议性的文件夹,用于存放您的主题所依赖的第三方JavaScript库(如jQuery, Lodash, GSAP等)或CSS框架(如Bootstrap, Tailwind CSS预编译文件等)。
将这些库文件放在此处并使用相对路径(如 lib/your-library.js
)在 main.html
中引用,有助于保持项目结构的整洁。
2.6 assets/
- 资源文件夹
这也是一个建议性的文件夹,用于存放主题中使用的静态资源,如:
- 图片 (JPG, PNG, SVG, WEBP等)
- 字体文件 (TTF, OTF, WOFF, WOFF2等)
- 音频文件 (如果主题内包含简短音效,但复杂音频管理推荐使用白噪音API)
- 其他媒体文件
同样,使用相对路径(如 assets/my-image.png
)在 main.html
或CSS中引用这些资源。
通过理解和运用以上文件结构及API,您就可以开始构建功能丰富、交互流畅的个性化专注主题了。记得在开发过程中频繁测试,并关注Doing开发者文档的更新~ 💡