当前位置: 首页 > news >正文

MailSpring

workspace-store

constructor

它的constructor注册了很多事件

constructor() {super();this._resetInstanceVars();this._preferredLayoutMode = AppEnv.config.get('core.workspace.mode');//当用户选择根工作表(root sheet)时,比如从侧边栏点击"收件箱"、"已发送"等主要视图,该方法会清空当前的工作表栈,并将选中的根工作表推入栈中。这是工作区导航的基础操作this.listenTo(Actions.selectRootSheet, this._onSelectRootSheet);//处理焦点设置事件,比如用户点击某个邮件线程或文,在列表模式下,会根据焦点变化自动推入或弹出相应的工作表,例如:点击邮件线程时自动推入 Thread 工作表,取消选择时弹出this.listenTo(Actions.setFocus, this._onSetFocus);// 处理工作区位置的显示/隐藏切换, 比如用户隐藏侧边栏、工具栏等界面元素, 将隐藏状态保存到配置中,并在界面上反映这些变化this.listenTo(Actions.toggleWorkspaceLocationHidden, this._onToggleLocationHidden);//处理工作区位置的打开操作 ,如果某个位置被隐藏了,打开操作会取消隐藏状态,确保用户请求的界面元素能够正常显示this.listenTo(Actions.openWorkspaceLocation, this._onOpenWorkspaceLocation);//处理工作表栈的弹出操作,比如用户点击返回按钮,从当前工作表返回到上一个工作表,这是导航栈的标准操作this.listenTo(Actions.popSheet, this.popSheet);//处理返回到根工作表的操作,比如用户按 Home 键或点击"返回主页"按钮,清空工作表栈,只保留根工作表this.listenTo(Actions.popToRootSheet, this.popToRootSheet);//处理工作表栈的推入操作,比如用户点击某个邮件打开详情页面,将新的工作表推入栈中,实现页面导航this.listenTo(Actions.pushSheet, this.pushSheet);//从应用环境获取窗口类型设置 比如 'main' - 主窗口 'emptyWindow' - 空窗口(用于特殊用途) 'onboarding' - 引导窗口const { windowType } = AppEnv.getLoadSettings();// 禁用视觉缩放功能
//设置缩放级别的最小值和最大值
//参数 (1, 1) 表示:
//最小缩放级别 = 1(100%)
//最大缩放级别 = 1(100%)
//作用:禁用双击缩放和捏合缩放功能,确保界面保持固定的缩放比例webFrame.setVisualZoomLevelLimits(1, 1);//立即应用用户设置的界面缩放this._applyDesiredScale();//监听界面缩放配置的变化AppEnv.config.observe('core.workspace.interfaceZoom', this._applyDesiredScale);if (windowType === 'emptyWindow') {
//空窗口通常用于特殊用途,比如弹出窗口或模态框 ,为空窗口设置窗口属性接收回调AppEnv.onWindowPropsReceived(this._applyDesiredScale);}if (AppEnv.isMainWindow()) {
//重建快捷键绑定
//调用 _rebuildShortcuts 方法来重新设置快捷键
//只有在主窗口中才需要设置快捷键,因为快捷键主要在主界面中使用this._rebuildShortcuts();}}

this._resetInstanceVars()

_resetInstanceVars() {this.Location = Location = {} as any;this.Sheet = Sheet = {} as SheetSet;// 新增 AccountSidebarSearchBar 插入点,补全 Toolbar 字段避免类型报错Location.AccountSidebarSearchBar = { id: 'AccountSidebarSearchBar', Toolbar: {} };// 新增 AccountSidebarClassification 插入点,补全 Toolbar 字段避免类型报错Location.AccountSidebarClassification = { id: 'AccountSidebarClassification', Toolbar: {} };this._hiddenLocations = AppEnv.config.get('core.workspace.hiddenLocations') || {};this._sheetStack = [];if (AppEnv.isMainWindow()) {//判断是主窗口this.defineSheet('Global');this.defineSheet('Threads',{ root: true },{list: ['RootSidebar', 'ThreadList'],split: ['RootSidebar', 'ThreadList', 'MessageList', 'MessageListSidebar'],splitVertical: ['RootSidebar', 'ThreadList', 'MessageListSidebar'],});this.defineSheet('Thread', {}, { list: ['MessageList', 'MessageListSidebar'] });} else {this.defineSheet('Global');}}

this.defineSheet

 defineSheet(id,options: Partial<SheetDeclaration> = {},columns: { [mode: string]: string[] } = {}) {Sheet[id] = {id,columns: {},supportedModes: Object.keys(columns),//支持的模式,比如:list、split、splitVerticalicon: options.icon,name: options.name,root: options.root,//是否是根工作表sidebarComponent: options.sidebarComponent,// 支持自定义侧边栏内容Toolbar: {Left: { id: `Sheet:${id}:Toolbar:Left` },Right: { id: `Sheet:${id}:Toolbar:Right` },},Header: { id: `Sheet:${id}:Header` },Footer: { id: `Sheet:${id}:Footer` },};// Make sure all the locations have definitions so that packages// can register things into these locations and their toolbars.for (const [mode, cols] of Object.entries(columns)) {Sheet[id].columns[mode] = [];for (const col of cols) {if (Location[col] == null) {Location[col] = { id: `${col}`, Toolbar: { id: `${col}:Toolbar` } };}Sheet[id].columns[mode].push(Location[col]);}}if (options.root && !this.rootSheet() && !(options as any).silent) {this._onSelectRootSheet(Sheet[id]);}//当短时间内多次调用 triggerDebounced() 时,只有最后一次调用会在 1 毫秒延迟后执行 //this.trigger(this)。this.triggerDebounced();}

代码解析:

if (options.root && !this.rootSheet() && !(options as any).silent) {this._onSelectRootSheet(Sheet[id]);
}

条件判断详解

1. options.root

含义:检查当前定义的工作表是否为根工作表

作用:

  • 只有根工作表才会被自动选中
  • 根工作表通常显示在侧边栏中,如"收件箱"、"已发送"等
  • 非根工作表(如邮件详情页面)不会被自动选中
2. !this.rootSheet()

含义:检查当前是否还没有根工作表被选中

作用:

  • this.rootSheet() 返回当前工作表栈中的第一个工作表(根工作表)
  • !this.rootSheet() 表示当前没有根工作表
  • 确保只有在没有根工作表时才自动选择一个
3. !(options as any).silent

含义:检查是否不是静默模式

作用:

  • silent 选项用于控制是否静默创建工作表
  • 静默模式下不会触发自动选择
  • 通常用于初始化时避免不必要的状态变化

整体逻辑

这个条件判断确保:

  1. 只处理根工作表:只有标记为 root: true 的工作表才会被考虑
  1. 避免重复选择:如果已经有根工作表被选中,就不再自动选择新的
  1. 支持静默模式:通过 silent 选项可以控制是否自动选择

执行操作

当条件满足时,调用:

this._onSelectRootSheet(Sheet[id]);

这会:

  1. 清空当前工作表栈:this._sheetStack = []
  1. 将新定义的根工作表推入栈中:this._sheetStack.push(sheet)
  1. 触发状态更新:this.trigger(this)

实际应用场景

场景1:应用启动时
// 在 _resetInstanceVars() 中
this.defineSheet('Threads',{ root: true }, // 根工作表{list: ['RootSidebar', 'ThreadList'],split: ['RootSidebar', 'ThreadList', 'MessageList', 'MessageListSidebar'],splitVertical: ['RootSidebar', 'ThreadList', 'MessageListSidebar'],}
);

  • 由于 options.root 为 true
  • 且当前没有根工作表(!this.rootSheet() 为 true)
  • 且不是静默模式(!(options as any).silent 为 true)
  • 所以会自动选择 Threads 工作表作为初始视图
场景2:静默创建
this.defineSheet('Global', { root: true, silent: true });
  • 即使 root 为 true,但由于 silent 为 true
  • 不会自动选择该工作表
  • 用于初始化时避免触发不必要的状态变化
场景3:已有根工作表

// 假设当前已经有 Threads 作为根工作表this.defineSheet('Preferences', { root: true });

  • 由于 !this.rootSheet() 为 false(已有根工作表)
  • 不会自动选择 Preferences 工作表
  • 用户需要手动选择才能切换到偏好设置

设计目的

这种设计确保了:

  1. 应用启动时有默认视图:自动选择第一个根工作表
  1. 避免状态冲突:不会同时选择多个根工作表
  1. 支持灵活初始化:通过 silent 选项控制初始化行为
  1. 用户体验良好:应用启动后立即显示有用的界面

这是 Mailspring 工作区管理系统的核心逻辑之一,确保了应用启动时的正确初始化和用户界面的合理展示。

this.defineSheet('Threads',{ root: true }, // 根工作表{list: ['RootSidebar', 'ThreadList'],split: ['RootSidebar', 'ThreadList', 'MessageList', 'MessageListSidebar'],splitVertical: ['RootSidebar', 'ThreadList', 'MessageListSidebar'],}
);通过defineSheet转换Sheet.Threads = {id: 'Threads',columns: {list: [RootSidebar, ThreadList],split: [RootSidebar, ThreadList, MessageList, MessageListSidebar],splitVertical: [RootSidebar, ThreadList, MessageListSidebar]},supportedModes: ['list', 'split', 'splitVertical'],icon: undefined, // 从 options 传入name: undefined, // 从 options 传入root: true,sidebarComponent: undefined, // 从 options 传入Toolbar: {Left: { id: 'Sheet:Threads:Toolbar:Left' },Right: { id: 'Sheet:Threads:Toolbar:Right' }},Header: { id: 'Sheet:Threads:Header' },Footer: { id: 'Sheet:Threads:Footer' }
}defineSheet('Global')
defineSheet('Threads',{ root: true },{list: ['RootSidebar', 'ThreadList'],split: ['RootSidebar', 'ThreadList', 'MessageList', 'MessageListSidebar'],splitVertical: ['RootSidebar', 'ThreadList', 'MessageListSidebar'],}
);
defineSheet('Thread', {}, { list: ['MessageList', 'MessageListSidebar'] });{"Global": {"id": "Global","columns": {},"supportedModes": [],"Toolbar": {"Left": {"id": "Sheet:Global:Toolbar:Left"},"Right": {"id": "Sheet:Global:Toolbar:Right"}},"Header": {"id": "Sheet:Global:Header"},"Footer": {"id": "Sheet:Global:Footer"}},"Threads": {"id": "Threads","columns": {"list": [{"id": "RootSidebar","Toolbar": {"id": "RootSidebar:Toolbar"}},{"id": "ThreadList","Toolbar": {"id": "ThreadList:Toolbar"}}],"split": [{"id": "RootSidebar","Toolbar": {"id": "RootSidebar:Toolbar"}},{"id": "ThreadList","Toolbar": {"id": "ThreadList:Toolbar"}},{"id": "MessageList","Toolbar": {"id": "MessageList:Toolbar"}},{"id": "MessageListSidebar","Toolbar": {"id": "MessageListSidebar:Toolbar"}}],"splitVertical": [{"id": "RootSidebar","Toolbar": {"id": "RootSidebar:Toolbar"}},{"id": "ThreadList","Toolbar": {"id": "ThreadList:Toolbar"}},{"id": "MessageListSidebar","Toolbar": {"id": "MessageListSidebar:Toolbar"}}]},"supportedModes": ["list","split","splitVertical"],"root": true,"Toolbar": {"Left": {"id": "Sheet:Threads:Toolbar:Left"},"Right": {"id": "Sheet:Threads:Toolbar:Right"}},"Header": {"id": "Sheet:Threads:Header"},"Footer": {"id": "Sheet:Threads:Footer"}},"Thread": {"id": "Thread","columns": {"list": [{"id": "MessageList","Toolbar": {"id": "MessageList:Toolbar"}},{"id": "MessageListSidebar","Toolbar": {"id": "MessageListSidebar:Toolbar"}}]},"supportedModes": ["list"],"Toolbar": {"Left": {"id": "Sheet:Thread:Toolbar:Left"},"Right": {"id": "Sheet:Thread:Toolbar:Right"}},"Header": {"id": "Sheet:Thread:Header"},"Footer": {"id": "Sheet:Thread:Footer"}}
}

http://www.lryc.cn/news/587410.html

相关文章:

  • C++--unordered_set和unordered_map的使用
  • 基于 STM32H743VIT6 的边缘 AI 实践:猫咪叫声分类 CNN 网络部署实战(已验证)中一些bug总结
  • Linux的 iproute2 配置:以太网(Ethernet)、绑定(Bond)、虚拟局域网(VLAN)、网桥(Bridge)笔记250713
  • python3的可变参数如何传递元组和字典
  • 第七章 算法题
  • 016_Token计数与成本管理
  • python:使用openpyxl库,实现excel表格的创建、查询(读取)、修改、插入数据
  • 在新版本的微信开发者工具中使用npm包
  • 开源工具DeepFilterNet:实时语音降噪
  • AI驱动的软件工程(上):人机协同的设计与建模
  • Vue 3 TypeScript 接口(Interface)使用
  • (一)SAP Group Reporting (GR) 集团财务合并解决方案套件概述
  • 数智管理学(三十三)
  • [论文阅读] 软件工程 | 首个德语软件工程情感分析黄金标准数据集:构建与价值解析
  • 【读书笔记】《Effective Modern C++》第二章:auto
  • 【论文阅读】Think Only When You Need with Large Hybrid-Reasoning Models
  • Datawhale AI 夏令营2025科大讯飞AI大赛<夏令营:用AI做带货视频评论分析>
  • 业务访问控制-ACL与包过滤
  • 【OpenGL ES】手撕一个mini版的Android native渲染框架
  • 串口学习和蓝牙通信HC05(第八天)
  • AI交互中的礼貌用语:“谢谢“的效用与代价分析
  • 09.获取 Python 列表的首尾元素与切片技巧
  • LLM大模型微调技术全景:从IFT、SFT到RLHF、DPO与PPO强化学习
  • 华擎B150M Pro4S魔改bios上8代U
  • AutoLabor-ROS-Python 学习记录——第一章 ROS概述与环境搭建
  • vue3 el-select默认选中
  • (33)记录描述窗体组件属性的枚举量 enum Qt :: WidgetAttribute, 简记为 WA_
  • 大模型微调(一):基于Swift框架进行自我认知微调(使用Lora微调Qwen3-8B模型)
  • MCU中的系统控制器(System Controller)是什么?
  • pthread_mutex_unlock函数的概念和用法