Skip to content

专注主题开发 预发布版本

更新时间: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交互逻辑。

核心职责:

  1. 界面渲染:构建用户所见的计时界面,包括时间显示、控制按钮、背景、动画效果等。
  2. 数据展示:通过JavaScript API从Doing应用获取实时数据(如计时器状态、剩余时间、设备信息等)并展示在界面上。
  3. 用户交互:响应用户的操作(如点击按钮),并通过JavaScript API调用Doing应用的内置功能(如暂停/继续、全屏、打开白噪音等)。
  4. 动态更新:根据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 中定义的、用户可自定义配置项的默认值

使用流程:

  1. 定义配置项 (info.json): 您首先需要在 info.jsonsetting 数组中定义每个配置项的元数据,包括其类型、标题、标识名(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"            // (可选) 图标代码
    }
  2. 提供默认值 (setting/settings.json): 然后在 setting/settings.json 文件中,为该 preferenceName 提供一个初始默认值。

    示例 setting/settings.json

    json
    {
        "backgroundBlur": "4.3"
    }
  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开发者文档的更新~ 💡