GitHub Desktop 的跨平台 UI
GitHub Desktop 的跨平台 UI
图比较是 GitHub Desktop 的核心功能. 它驱动你分支的交互,显示你的改动对根分支的影响。
很多复杂的应用程序用户界面都做得很易用。以动画的方式解释提交,同步,合并的效果。
为 OS X 和 Windows 提供独立的代码库和设计,我们知道共享代码是不可或缺的。像图像这样复杂的处理,实现两次将是一个很大的负担。
跨平台代码对我们来说不是全新的:举例来说,代码基于git & libgit2。共享用户界面尊重了每个平台的不同方式。
幸运地是,在 Electron 应用中作为一个可重用的 web 组件,比对图已经被原型化。我们知道我们可以在 OS X 主机上实现一个本地的 web 视图,并且在 Windows 上也提供了支持。
这里,我们会这样做。
共享性实现
所有的 GitHub 桌面实现,作为 submodule,都是参考图像比较。这为图像比较和其辅助带来了完整的 HTML/CoffeeScript/SASS 的来源,就像调试和建立脚本。
这些中的大多数对于运行应用时不太必要的,因此要建立脚本,把来源编译成应用中嵌入的可分配的 HTML/JavaScript/CSS 文件。
在 OS X 系统中,我们用苹果的 WebView 在 UI 中区整合图像比较。在 Windows 系统中中,我们发现在 .NET WebBrowser 控制中的初始探索是不可运行的,所以我们在其中嵌入 CefSharp 并使用它的ChromiumWebBrowser(Chromium 网络浏览器)。当这些令我们的文件大小增加时,WebView 和衍生自 Webkit 内核的 ChromiumWebBrowser 能简化开发和调试图像比较的变更。一般情况下,在 OS X 系统下进行图像比较的开发者不必担心这些应用能否在 Windows 下运行,反之亦然。
共享接口
我们必须考虑到在全平台上的图像比较 API,然而,重要的更改必须被整合在应用的各处。重要更改是前期讨论的结果,这是一个问题,一是表现在拉取式请求中的调出,二是确保熟悉对其他已经具有机会进行评论的平台。
我们有意识地把图像比较 API 控制得狭窄和专一。其综合流程如下:
-
提取流动的和作为基础的分支。
-
应用请求图像比较描绘出比较。
-
图像比较请求它的分支代表(其应用)来在每一分支中进行提交的批处理。
-
应用通过提取提交并将它们移出图像比较。
-
重复步骤 3 和 4 直到图像比较填充了视图的宽度(或稍微超出一点填充空间),又或者是达到了分支点(分支汇聚的地方),表明应用发送了 0 条提交。
-
如果图像比较已经不能到达分支点,在滚动和重设左侧尺寸来展现更多的图像的情况下,重复步骤3到步骤5。
图像比较仍会出现单分支,或者拉取式请求。这多少会带来不同的影响,但整体流程仍与原来的很相似。
应用需要支持以下交互:
-
当新的提交出现时,无论是同步还是提交,应用都要把它们引入图像比较。
-
当用户的鼠标指针经过或选择了提交图像比较,和按下了按钮,图像比较会通知其交互代表(应用)。
-
按钮的动作执行通常应该是异步的,以便于图像比较能够提示那个应用正在运行中。应用能够命令图像比较提示什么信息,和什么时候停止提示。
-
应用能够改变按钮的功能,比如,当分支已经远程发布时,把“发布”按钮变成“同步”按钮。
自从所有的应用必须执行自身的流程,它们也共享周围粗略的架构,这包括了以下:
-
当有命令存在时(比如,用户作出了提交命令),计算代表图像状态的值。
-
分离连续状态。
-
通过询问图像比较来执行一些动作,解释其不同之处。例如,如果两个状态属于了不同的分支,应用会询问图像比较去描绘新的比较(或者分支,又或者是拉取式请求。如果他们是属于同一个分支,但随着提交命令而变化,应用就不会去询问图像比较,而是去递增地插入新的提交。
非共享的实现
虽然整体流程和架构是共享的,但其实现往往是不一样的。比如,虽然所有平台都是用 WebKit 浏览器核心,但各自的桥接 API 是很不一样的。
在 OS X 平台上,JavaScript 核心的 API 允许我在 Object-C,Swift 和 JavaScript 之间传递任意的对象,函数和数组。本地代码可以在 JavaScript 对象中调用方法,而 JavaScript 代码也可以在本地对象中调用方法,不需要任何特殊的控制手段。我们也可以定义协议去指定对象的某个属性来被桥接。
CefSharp,在另一方面,没有桥接函数的数组。JavaScript 对象能够调用本地对象的方法,但不能调用本地对象的属性。本地对象不能调用 JavaScript 对象的方法;作为替代,你可以访问 ChromeWebBrowser 去评估 JavaScript 来源的字符串。因为图像比较拥有巨大的异步性,需要回收和数组,这导致在构建时,一系列 JavaScript 的垫片会进入图像比较。
在加载中,shims 是比较图片应用的代表。当比较图形的要求提交时,它会通过一个回调将提交的文件回传。Shims 将回传值存入一个专用表格中获得一个密钥,调用应用并将密钥传递。当应用程序获得了请求后,它会调用回传值,并传递密钥和一组请求数组。
shims.getCommitsBefore = function (name, sha, callback) { callbacks[key(name, sha)] = callback; window.native.getCommitsBefore(name, sha); }
因为 CefSharp 不能传递,这需要将程序模型序列化,提交请求到 JSON 的比较图。与 OS X 的进程相比(请求的数组可以被直接传递),它稍稍显得不方便,但它有一个优势:比较图和应用程序相互隔绝,不受期望状态的改变而影响。
Browser.RunJsAsync("shims.didGetCommitsBefore(" + ToJson(name) + ", " + ToJson(sha) + ", " + ToJson(commits) + ")");
最后,应用调用到 shims,传递 commits 的序列号数组,shims 把 commits 提交到比较图。
shims.didGetCommitsBefore = function (name, sha, commits) { callbacks[key(name, sha)](commits); delete callbacks[key(name, sha)]; }
我们同时使用 CSS shims 来调整比较图的外观来适应主机平台的外观和感觉。例如,在 Windows 上,按钮需要一个平面外观,但是在 OS X 上,需要有轻微的梯度。同样,Windows 的文本是 Segoe UI,OS X 的文本是 Helvetica Neue。这可以帮助我们确保在不同平台之间的共享效应不会是一个最小公分母体验。
前瞻
除了对照图,教程,和许多共享的体系结构,大多数的实现在两个平台上仍然是不同的。也许我们所做的覆盖 Mac 版本 GitHub 和 Windows 版本 GitHub 的桌面程序迭代相对于全部重写是有重大好处的方式。这反过来又使我们保持在 GitHub 桌面上的更新,不至分散我们过多的注意力。
我们在这里的迭代方法,是我们开始向前迭代。有很多对照图,让我们有更多东西在不同的平台间分享。向1.1致敬!