右舷

宇宙,人类最后的边疆

去年春节前,我在楼下溜锅,偶然看到小区门口倒闭商店一条街上竖起了一枚健身房的招牌。春节后的四五月间,这家健身房顶着疫情开放了。本着健身房都开到楼下了,不办张卡不好意思的精神。在离开北京之后,第一次拥有了一张健身卡。后来又买了个课,练习基本动作要领和注意事项(主要是防止受伤)。课程结束后,就进入了自己训练的时间。

于是就需要自己做每次训练的动作计划和训练记录,比较科学,满足数据记录控的心理需求。类似于这种纸质记录。

纸质健身记录

然而并不容易找到符合需求的 app,我需要的核心功能是练前自己制定计划,训练中能记录次数。市面上的 app大多数都不支持自己定计划,提供的都是定好的刷脂增肌计划,而且太多带有各种社交属性的不重要功能。

我的需求非常简单,记录动作的重量和次数,休息时间帮我计时就可以了,于是想自己做一个算了。

这个时间就刚好找到了训记,训记的模版功能完美地契合了我的需求,练前计划和训练中的计时功能都相当简单直接,一目了然。

开发者看上去自己是个健身爱好者,所以我作为一个初学者,在使用训记的过程中也慢慢接受了一些作者融入到功能中的帮助。

统计功能

比如统计功能除了传统的训练内容罗列之后,还有一个图形化的训练部分展示,直观地展示出没有训练到的部分。
统计

低分化和5X5

我上的健身课是一种高分化的训练计划,所以高分化,是训练计划的分解程度比较高,练腿的时候只练腿,练胸的时候只练胸,好处是在体力有限的条件下,对特定部分的刺激比较深。但是初学者使用高分化有两大劣势,一个是你没有足够的实力刺激对应肌肉到特别高的地址,另一个是你没有时间经常进行训练,所以每两次刺激相同肌肉的间隔时间过长。

所以在使用了一两天自己的模版之后,我就换用了训记内置的5X5计划。这看上去是和我最初口口声声说的一定要使用自定计划相违背,但5X5在原理上比较能说服我,并且非常重要的是,它是一个一次训练40分钟左右的计划,这意味着我可以在中午吃完午饭后半小时进行训练,然后在下午上班前回到公司。

这样我就能进行每周一三五的三次训练,这明显比每周末两次训练科学合理得多。

付费订阅

训记是免费使用付费订阅的,它的免费功能对大部分人来说已经够用了,说实话我不知道它的付费功能有太多的吸引力,但是我希望它能长久的运营下去,订阅了每年的会员计划。

可能是一个月之前,有个用户发消息给我,说 iTimeLog 编辑事件时是无法操作秒数的,而他是个处女座,希望不要看到事件后面跟着稀稀拉拉的秒数,希望可能把它们都清零。但 iPhone 自带的时间调整滚轮控件不支持修改秒,于是我自定义了时间修改操作,发了一个小版本。

然而,三天后,剑飞大佬给我发一份用户反馈…

1.时间采用24小时制,需要滑动的数字多。不如上午下午智能
2.分针0-59不可以循环滑动,只能从0-59,不能回到0..1等,太麻烦了
3.每日时间没有统计一共记录了多少小时,很难查漏补缺看到具体哪一天缺了多久时间没有补
4.看不到星期几,查看时间记录和补时间记录 对应关系不强
5.建议让用户自行选择是否切换升级至新版本,而不是直接突然更换

这说明系统控件在操作上还是做了很多考虑,一换成自定义控件就会有用户发现不方便的地方,但为了能操作秒数,只好自定义一个,这位用户的反馈,除了第五点是 iPhone 的系统设置之后,其它四点都是可优化的地方。用户还说希望能降到以前的版本,闻者伤心。

于是这两天我找出来系统的控件实际操作了一下,做一些小优化:

  1. 时间依然是 24小时,但是最左边增加了上午下午的选择,跟小时数是连动的。
  2. 小时,分钟,秒都可以循环滚动。
  3. 统计界面显示统计小时数, 这个以前是有的,这次改错了。
  4. 日统计界面,时间显示改为 2020-09-29 星期一,而不是 2020-09-29 ~ 2020-09-29 的格式。

同时,我注意到用户有查缺补漏的需求,iTimeLog 在这部分提供的便利还是很弱的(我们希望的是即时记录)。补漏本身比较麻烦,补前两天的漏就更麻烦了。于是这版我们上线了一个对应的功能。

在日统计界面,总计时间旁边有一个小小的加号按钮,点击它,将对进入新的补事件界面,在这个界面,我们列出了对应日期的已统计事件列表,在已统计界面的时间间隙中,插入了可添加事件的空间,点击对应的是时间块,就可以添加漏计的时间了。

iTimeLog 是一个业余项目,现在的版本改动已经不大了,但它的改动还是向着更方便易用的方向去的(一个收费应用其实也没有其它更多想法),可能由于某些时候设计的失误或测试不足会有一些问题上线。希望用户不吝自己的时间,升级它,使用最新的版本,帮助它继续进化。如果升级之后觉得有问题,请随便通知我们。

中秋快乐。
国庆快乐。

iTimeLog 支持对事件进行分类,一般来说,用户都是使用自然直观的分类法,比如说事件是 《穿越非洲两百年》,那么类型就是读书,事件是地铁,那么类型就是通勤。这样当然可以,也是很多人使用的方法。

前几天剑飞给我发过一张用户的使用界面,事件类型部分写着投资,消费之类的,刚好跟我一直在使用的分类法一样。很久以前我写 blog 介绍过这种分类法,但现在找不到了,刚好借这个由头再写一遍。

这种方法初来自胜间和代的《时间投资法》这本书,主要的想法是指时间的使用分为投资,消费,浪费,闲耗,这种分类更加主观和个人化。对于想通过时间记录来改进时间分配的人来说更加有用。

下面我试着来说明一下四种分类的事件分法。我是一名软件开发者,那么对我来说,四种事件分别是:

投资

一般来说,这里的投资时间是重要而不紧急的事,使用当下的时间为了更多地节省未来的时间。比如说使用 iTimeLog 记录时间就可以看作一种投资。很多人都说记录时间这个动作就是额外的时间花费,确实如此,但对记录下来的时间进行分析,发现时间黑洞并改进时间分配的结果,可能在未来节省下来的时间多倍于记录和分析所花费的时间。我一般把软件开发技能提升,身体锻炼之类的事件记为投资事件。

消费

消费事件处于重要紧急象限。它是当下为了收益必须要做的事,很多时候不是为了未来,至少主要目的不是为了未来进行累积。比如说你驾轻就熟的工作。工作很多时候是出卖时间换取收益,当然大部分情况下,工作会使工作技能和经验提升,但这可能不是工作的最主要目的,工作的日的是尽可能多快好省地完成一件事。所以我一般把日常工作和个人的项目比如 iTimeLog 的开发都记为消费。

闲耗

闲耗是不重要且不紧急的事,或者说是不是必须做的事。胜间和代举的例子是无意义的闲聊,看个肥皂剧等等。但我不太喜欢这个分类名称,在我的系统中,这些事件记录消遣,胜间和代认为应该最大化地缩减这个时间,但我没那么苦行,我觉得消遣是必要的。所以我个人不特别刻意控制这个时间。我的消遣类事件包括美剧,漫画,听播客等。

浪费

浪费是指不重要但紧急的事,很多时候把紧急理解为不得不做的事可能逻辑上更加顺畅。浪费和消遣的区别是消遣多多少少还是能让人愉悦的。浪费对我来说更加耗神,比如在北京的时候挤地铁上班,通勤时间跟交税一样是不可避免的,但可能通过一些办法来缩减,比如通勤是听一些播客,就把浪费转为消遣,看一些专业文章,就浪费转为投资。还有一种做法,就是多花点钱搬到公司附近住,就大量减少了系统中的浪费时间。

这种分类法跟自然的分类法最重要的区别是主观意识更加重要,相同的一件事,对不同的人属于不同的分类。比如健身,对你我来说肯定是一种投资,更好的身体带来更好的精神状态,使得在处理消费类事务时更有效率。对于健身教练来说可能就是消费,是他们工作的一部分。这样统计出来的分类数据更有指导意义,比如胜间和代就推荐每天花30%的时间在投资上。

在《时间投资法》这本书中,作者认为时间管理的关键就是如何将“浪费/闲耗”的时间转化为“投资”的时间,促成有意义的“消费” 。

希望这样的想法,对你的时间管理系统有所启发。

switch

在最近发布的 iTimeLog 4.8.5 中,我们终于支持快捷指令了。
快捷指令是 iOS 12 开始支持的效率工具,可以配合应用快速完成各种任务。这一次,我们让 iTimeLog 可以和快捷指令配合,使时间记录更加方便。这种配合的基本想法,就是在通过系统的快捷指令功能,在进行某些操作的时候,同时触发 iTimeLog 开始时间记录,但比较遗憾的事,并不是所有的结束记录工作都能触发。

这一版中, 我们先开放了五个指令:

  • 开始一个事件
    在 iTimeLog 中开始 事件名类型
  • 完成一个事件
    在 iTimeLog 中完成 事件名类型,如果这一事件并没有在记录,忽略它。
  • 完成正进行中事件
    完成进行中的事件
  • 添加或结束事件
    在 iTimeLog 中添加 事件名类型,如果相同事件正在进行,完成它
  • 添加或继续事件
    在 iTimeLog 中添加 事件名类型,如果相同事件正在进行,就继续记录

安装了 4.8.5 以上版本之后,你就会在快捷指定的 App 项目中看到 iTimeLog,里面包含了这五条指令。
下面我们通过几个例子看看 iTimeLog 如何与快捷指令配合。

上班和下班

自动化

快捷指令的自动化 tab 支持进入一个地点和离开一个地点时触发,就是说你可以把你的公司作为一个触发条件,粗略地记录你在公司上班的时间。

在快捷指令的自动化 tab 中,创建一条个人自动化,选行程中的到达项目,选取位置和时间,然后添加一条「添加或结束事件」就可以了。

当你在特定时间段进入公司时,快捷指定会通知你已进入公司,是否添加一个「工作」记录,你只需要点击运行就可以了,iTimeLog 会帮你记录一件开始上班的记录,而离开公司时,快捷指定也会询问你是否需要结束这条「工作」记录。

稍微麻烦一点的是,地点触发的自动化指定是无法设置成不询问直接记录的,可能是苹果不希望用户在不知情的情况下被执行了一些操作。

统计 app 使用时间

在 iOS 中,由于沙盒机制的存在,app 其实不知道有哪些其它的 app 开始运行的。但是在快捷指令的自动化中,有一项是 「打开 app」时,所以我们就可以设置在打开指定的 app 时,触发 iTimeLog 开始记录事件。

例如,我一般用 overcast 听 podcasts,所以我就设置了一条自动化指令,当打开 overcast 时,自动开始记录 「日谈公园:消遣」,在这里我用的是添加或继续事件,而不是开始一个事件指令,因为「打开 app」这一个触发项在 app 从后台到前台的时候也会触发,而我不想在这些时刻都直接开始一条新的记录,使我的日常记录无限变碎。

日谈公园

这是最初的使用方式,几天后,我发现快捷指令是可以放到主屏幕上的,所以最终我改成了同时运行两条指令这种方式,即,我编辑了一条指令,当它执行时,同时记录事件和打开对应的 app,然后我把它放到主屏幕上。
主屏
这样,当我想看最新一集星际迷航:航海家号时,我就直接点击星际迷航图标,系统帮我开始一条 iTimeLog 记录,并同时打开 nplayer。

跟 NFC 一起使用

贴了贴纸的 switch

上面说的是在 iPhone 中跟其它 app 协同的记录,这次触发我们做这个捷径功能的其实是 NFC, 新的 iPhone 是支持 NFC 的,最近我看了一些视频,发现 NFC 贴纸是一个非常便宜的东西,而快捷指令是支持 NFC 触发的。这就把 iTimeLog 跟现实世界联系了起来。

自动化

所以我在我的 Mac 上, kindle 上, switch 上和一把椅子上都贴上了 NFC 贴纸。当我的手机扫到 kindle 上时, iTimeLog 开始记录我正在看的电子书,扫椅子时则是最近的一本纸质书,而扫一下 mac,开始记录工作。

在这里,我使用的是「添加或完成事件」指令,当我放下书或者 switch 时,拿手机再扫一下贴纸,就可以完成这条记录了。

接下来

我们应该会继续探索使用快捷指令记录时间的方式,在后续版本中推出更多可用的指定,让时间记录这件事更加自动化。

需求

需求很简单,当一个内容超过 4 行时,默认显示 4 行,并显示一个展开按钮,占周完全展开,展开后显示一个收起按钮,点击收起到 4 行。

当然最直接的想法就是利用 YYLabeltruncationToken, truncationToken 天生的含义就是文本无法完整显示的时候接在文本后面作为提示的,默认的样式就是常见的,它是可以自定义的,比如说在这个需求出,就可以设置为展开和收起。

但有一个问题,如下图。


truncationToken是跟在文本后面的。它所跟随的文本行只到显示宽度的一半时,就会变成这样。这个应该是用 truncationToken 无法完成的设置。

于是考虑还是使用一个按钮来实现这个需求,那么问题两个,一个是按钮怎么定位,一个是怎么在文本中留出空间放按钮。

按钮定位很简单, 一直在 YYLabel 的右下角就好了,微调一下边距即可。关键的留空的问题,一开始想的是使用就用 truncationToken 来实现,把它设置为一个 N 个空格组成的字符串,比如 「 」,但是不生效, truncationToken 看起来忽略了纯的空字符串, 「 ab」就可以,空格后面跟实际的字符的话,空格也会作为 truncationToken 的一部分,但是只有空格就是被忽略。后来考虑用不可见字符 比如 \u000000 ,结果一样,被忽略了,CoreText 看起来相当智能。

后来发现了一个鸡贼的做法, truncationToken 是一个 NSAttributedString, 那就可以设置成实际的字符,但颜色设置为 clearColor,用这种方式实现不可见的占位,然后把按钮放在占位留出来的空间了,就实现了需求。

帕劳潜水轨迹图
轨迹

前段时间做了一些 fastlane 自动化脚本的工作,记一些搜索出来的东西。

修改 plist 中的一些普通属性

Xcode 一般用 Info.plist 来管理 project 的一些属性, 对 plist 的修改可以用 update_info_plist

1
2
3
4
update_info_plist(
plist_path: "./Runner/Info.plist",
display_name: 'iTimeLog'
)

改变 bundle id

如果用 update_Info_plist 来修改 bundle id , 会发现 plist 文件中 bundle id 变了,但是Build Setting 中的 product bundle identifier 没有变化。 在 Fastlane 中使用 update_app_identifier 来修改 bundle id, 同时 Info.plist 中不要显示地写 bundle id, 使用 $(PRODUCT_BUNDLE_IDENTIFIER) 引用 product bundle identifier 就好了。

1
2
3
4
5
update_app_identifier(
xcodeproj: "Runner.xcodeproj",
plist_path: "./Runner/Info.plist",
app_identifier: 'net.laihj.iTimeLog'
)

修改 url type, 遍历 plist 中的 array

对于 plist 中的 array,使用 block: proc do |plist|来遍历,找到相应的 key , 再修改。

1
2
3
4
5
6
7
update_info_plist( 
plist_path: "./Runner/Info.plist",
block: proc do |plist|
urlScheme = plist["CFBundleURLTypes"].find{|scheme| scheme["CFBundleURLName"] == "iTimeLog"}
urlScheme[:CFBundleURLSchemes] = [option[:scheme]]
end
)

修改 entitlements 的内容

项目文件中的 Associated Domains 写在 entitlements 文件中, 用文本打开后发现 entitlements 就是一个 XML 文件。 当成 plist 文件使用 update_plist 操作即可。

1
2
3
4
5
6
update_plist( 
plist_path: "./Runner/即燃.entitlements",
block: proc do |plist|
plist["com.apple.developer.associated-domains"] = [option[:domain]]
end
)

打包时指定 AppIcon

在 gym 打包时 通过 xcargs 参数修改 ASSETCATALOG_COMPILER_APPICON_NAME

1
2
3
gym(
xcargs: 'OTHER_SWIFT_FLAGS="-D PROFILE" ' + 'ASSETCATALOG_COMPILER_APPICON_NAME='+appicon,
)

2019年,我们终于支持 iPhone 的 today widget 了,today widget 就是 iPhone 的桌面小部件,在 iPhone X 系列中,滑到最左边就是 today widget的功能了,在非 X 系统 iPhone 中,需要下通知列表,再左滑才能看到。

iTimeLog 的 today widget 第一版,是一个快速输入系统。输入的简便是 iTimeLog录入设计 的最重要目标。

today

如图所示,iTimeLog 的 today widget 分为两个部分,用一条浅蓝色的线分割。上半部分第一条常驻按钮是添加一个新的事件,点击它将会调起 iTimeLog 的主程序,并且呼出键盘,接受你的输入。

第二条常驻元素是当前正在进行的事件,点击它将会完成这个事件的记录,如果当前没有记录事件,它的功能就和第一条常驻一样。

下半部分是常用输入事件备选项,一直以来, iTimeLog 都觉得将用户已输入的事件作为事件模板,自然形成最近一段时间的输入备选是一种合理的做法。这里也一样,这个桌面小部件的下半部分最多可以显示五个事件,这五个事件是 iTimeLog 中用户输入的最近五个事件列表,实测对于一个生活比较规律的人来说,可以覆盖 50% 以上的快速录入功能了。

在这个功能的开发过程中,我买了自己的第一台 X 系列 iPhone,一台红包的 iPhone Xr。实际使用中,我发现 today widget 的使用比想象中还要方便,在手机不解锁的情况下,你也可以在锁屏界面直接左滑使用这个功能。

图表是一种对数据的加工,目的是为了让你对你记录的数据有一种更直观的把握。

输入其实是为了输出数据进行检视,检视是为了改进工作流程。如果不做输出和检视,输入的数据就是死数据,输入所花费的时间也就白费了。

这一篇我们来介绍 iTimeLog 的图表,它们都是检视的辅助。

首页就是一张表

iTimeLog 的首页,是一个输入界面,同时它也是一张简单的基础时间消耗列表,这张列表中,以天为单位隔开,按时间顺序排列事件,并展示出每个事件的起止时间和时间消耗。

点击首页右上角进入第一个统计页面

(上图是以下两个界面的合并,app界面是分列表和饼图的)
第一个页面是事件的列表,简单直接但是不直观,点击右上角的按钮就进入了事件的统计列表。

在这张表中,我们把选定时间段内事件的消耗时间加起来,让你直接看到每天每周或每月的总体时间花费。

这张表中,我们还提供一张饼图,让你直接看到各个事件的时间使用比例,这样你就能看出这一天是生产的一天,还是休憩的一天。

列出事件详情

在统计界面中点击某个特定的事件,就进入了该事件的详细时间账单,这张账单显示出你使用 iTimeLog 以后在一件事件上付出的时间。

对于一些短期事件,比如读一本书之类的,也能非常方便地查看记录整体花费的时间。

单个事件的统计图表

柱状表显示每个时间段中,给事件付出的总使用时间。

同时多个时间段排列查看,也能看到这一事件的时间投出趋势,比如 iTimeLog 在最初比较密集开发的时候,每周大概要投入 20 个小时以上的业余时间,发布几版之后,主要功能稳定了,时间花费就降了下来。

这张事件的时间分布图,主要是显示你是否在正确的时间做重要的事情。

每个人都会有自己的高效时间和不高效的时间,在高效时间进行更有生产力的活动是一种更合理的选择。iTimeLog 其实并不希望给人压力,让人去尽力填满每天的 24 个小时,更希望通过统计数据,让人们对自己每天的 24 小时做出更合理的分配。

0%