Skip to content
ZZPBYPublic

About

[CN]极简、纯离线的安卓倒数日 / 倒计时日历。纪念日、生日、考试的天数倒数,支持桌面小组件、精确到分钟、标签、置顶、搜索排序与自定义主题色。不要任何权限、不联网、无广告、开源。 [EN]A minimal, fully offline countdown calendar for Android. Days until anniversaries, birthdays and exams — home-screen widget, minute precision, tags, pinning, search, sorting and themes. No permissions, no network, no ads. Open source.

Topics

Resources

Stars

9 stars

Watchers

1 watching

Forks

Repository files navigation

TickCount

Build License: MIT

一个极简、纯离线的安卓倒数日日历。在日历上点一天、起个名字,就能看到离那一天还有多久, 或者已经过去了多久。

English

约 2 MB · 零权限 · 纯离线 · 无广告 · 无账号 · 开源

首页:每条倒数日还剩多少天,已过去的收在下面 日历与那天的倒数日 两种桌面小组件

功能

  • 三个页面 —— 首页、日历、设置,底部一键切换。
  • 倒数日列表 —— 一卡一条:超大号的天数,加名称、标签和日期;过去的收在最下面。
  • 精确到分钟 —— 可以是全天,也可以指定到某时某分。
  • 每年重复 —— 生日、纪念日这类每年都会回来的日子设一次就够,列表、日历和提醒都按它下一次落的那天算。
  • 置顶与排序 —— 置顶的始终在最前;可按日期远近或添加时间排,选择会记住。
  • 搜索与筛选 —— 按名称、日期或时间搜,也能只看「7 天内」或某个标签。
  • 标签与颜色 —— 标签不限个数;颜色在色相条上调,不指定就用主题色。
  • 详情页 —— 年月日时分秒的完整拆分,以及置顶、日期、时间、备注和标签。
  • 备注 —— 每条倒数日可写一段备注,只在自己的详情页显示;列表、日历、桌面小组件和搜索都不显示。
  • 日历 —— 一天最多三个圆点;点一天看那天的倒数日,点月份标题快速翻月。
  • 长按卡片 —— 置顶、编辑或删除,删除前先确认。
  • 一键添加多个 —— 填间隔天数和个数,一次添加一串同名的倒数日。
  • 桌面小组件 —— 单个(时分秒实时跳动)和清单两种,随尺寸换排版;面板可选浅色 / 深色 / 跟随系统。
  • 通知与提示 —— 提醒时间和提前量只管全天倒数日,单条倒数日可以另设提前量;也能发一条测试通知。
  • 农历 —— 新建时可以按农历选日子(1900–2100,含闰月)。
  • 外观 —— 大圆角卡片配细描边、超大的天数层级;六套主题,外加自定义色相。
  • 中英双语 —— 跟随系统语言,也能在设置里手动选。
  • 备份与恢复 —— 全部数据导出 / 导入,可加密码;还能导出 .ics 给系统日历。
  • 更新日志 / 项目介绍 —— 应用内就能看。
  • 大字体 —— 跟随系统字体缩放,长高而不挤压文字。
  • 零权限、纯离线 —— 除可选的提醒外不申请任何权限;不联网、无统计。

一键添加多个

名字、备注、标签、颜色和时间只填一遍。新建时打开「一键添加多个」,再填两个数:

  • 间隔天数 —— 相邻两条之间差几天,1~3650 天。
  • 个数 —— 除了上面选的日期,还要再添加几条相同的,1~100 条。

上面选的日期本身也会添加一条,之后每条都比前一条多间隔那么多天。所以 10 月 14 日新建 「打副本」、间隔填 2、个数填 3,列表里就会出现 10 月 14、16、18、20 日共 4 条。

时间那一栏选的值,这一串里每一条都跟着走;全天就是全天,09:30 就是 09:30。写好的备注也一样。 这些条目算同一批,所以「按添加时间」排序时它们挨在一起,里面的先后仍按日期排。每一条都是独立的 倒数日,之后各自编辑或删除,互不影响。

倒计时的读法

目标是所选日期当地时间的 00:00;这条倒数日如果指定了某时某分,就以那个时刻为准。 每年重复的,取它下一次落到的那天:过了今年这一天,目标就变成明年的同一天(2 月 29 日 落到 28 日)。 这个时刻过去之后,同一套算法反向运行,标签从「还有」变成「已过去」;目标日当天显示的是 「今天已过」。

从最高位起,还没有开始计数的字段用短横线占位,所以一眼就能看出还剩多久:

剩余时间 显示
4 个月 11 天 6 时 30 分 15 秒 ----年04月11日 06时30分15秒
2 天 30 秒 ----年--月02日 00时00分30秒
3 年 4 个月 11 天 6 时 30 分 15 秒 0003年04月11日 06时30分15秒

年、月、天按日历算,小时、分、秒按流逝时间算,所以夏令时切换的那一天仍然算一整天, 哪怕它实际只有 23 或 25 小时。

桌面小组件

长按桌面空白处 → 添加小组件,里面有两个可选:

倒数日 · 单个 —— 再挑一个倒数日(列表里带时间,同名的两条不会挑混)。默认 4×2,拖大拖小 会自己换排版:拖扁了是「名字 + 天数 + 时钟」一行,拖大了再加上目标日期,并把天数拆成 「1年1个月4天」。点它直接打开这条倒数日。填了具体时间的倒数日,它也按那个时刻算,并在日期 那行写出时间(窄排版写在天数后面),和详情页一致。秒针由系统自己走,不额外唤醒应用。

倒数日 · 清单 —— 不用挑,它自己列出接下来要数的几条,从近到远,一行一条;点哪一行就 打开哪一条。填了具体时间的会写成「今天 09:30」。默认 4×2 放得下三行,拖高了最多四行, 行会撑满整个组件;没有要数的日子时显示一行提示。

两个组件的面板都在设置里的「桌面小组件」选:浅色、深色,或跟随系统。清单组件还能换字号 (小 / 标准 / 大);单个组件不跟着变,因为它的文字本来就撑满格子,用的是放得下的最大字号。

应用更新之后,两个组件会自己重画一遍,不用删掉重加。

两个都不需要任何权限。

下载

APK 发布在 Releases,也可以从 Actions 标签页里 任意一次成功的构建中下载产物。每个版本改了什么见 更新日志.txt。

编译

需要:

  • JDK 17
  • Android SDK Platform 37 和 Build Tools 36.0.0
  • 在 local.properties 里写好 SDK 路径,或导出 ANDROID_HOME
./gradlew testDebugUnitTest   # 单元测试
./gradlew assembleRelease     # APK -> app/build/outputs/apk/release/

Windows 下使用 gradlew.bat。

技术栈

语言 Kotlin 2.4.20
UI Jetpack Compose + Material 3(Compose BOM 2026.09.00)
构建 AGP 9.4.1、Gradle 9.6.0,版本集中在 gradle/libs.versions.toml
SDK compileSdk 37、targetSdk 36、minSdk 27
存储 SharedPreferences 里存一个小 JSON 文档
依赖 运行时仅 AndroidX 与 Compose

minSdk 为 27。java.time 在 API 26 就有了,主题里的 windowLightNavigationBar 在 27 也有了,所以既不需要 coreLibraryDesugaring,也不需要任何兼容垫片, 更不必把主题按版本拆成两份。

目录结构

app/src/main/java/io/github/zzpby/tickcount/
├── MainActivity.kt              边到边宿主 + 应用主题(含状态栏图标配色)
├── data/                        模型与持久化
│   ├── CountdownEvent.kt        倒数日模型:id / 日期 / 时间 / 备注 / 标签 / 颜色 / 置顶
│   ├── EventCodec.kt            倒数日记录的 JSON 读写,含旧格式迁移
│   ├── EventStore.kt            把上面那份文档存进 SharedPreferences
│   ├── SettingsStore.kt         主题、排序、语言与小组件外观的存储
│   ├── Backup.kt                备份文件的格式,以及导入的结果
│   └── BackupCrypto.kt          备份的密码加密(PBKDF2 + AES-GCM)
├── domain/                      纯逻辑,有单元测试
│   ├── Countdown.kt             年/月/天/时/分/秒 的拆解与占位格式化
│   ├── BatchAdd.kt              一键添加多个:按间隔天数铺开一串副本
│   ├── CalendarMath.kt          月历网格构造
│   ├── CountdownList.kt         列表排序、分段与天数距离
│   ├── Search.kt                搜索范围与匹配规则
│   ├── Changelog.kt             把更新日志拆成一个个版本
│   ├── Readme.kt                从 README 里抽取项目介绍的章节
│   ├── Ics.kt                   导出 .ics:把倒数日写成日历文件
│   ├── Lunar.kt                 农历表与公历/农历互转(1900–2100)
│   └── WidgetCountdown.kt       小组件的天数拆分、形态判定与清单挑选
└── ui/
    ├── MainViewModel.kt         状态 + 全进程唯一的那个时钟
    ├── TickCountApp.kt          根画面:三个屏幕的切换、返回键、各弹窗
    ├── AppDestinations.kt       底部三个按钮,以及应用能到的每一个屏幕
    ├── AppBottomBar.kt          底部栏:浮起的圆角卡片,里面三个按钮
    ├── SettingsScreen.kt        设置:分组的条目,语言和备份都在这里
    ├── AppTitleBar.kt           标题栏:返回 + 名字 + 动作槽
    ├── HomeScreen.kt            倒数日列表
    ├── CalendarScreen.kt        月历 + 选中那天的倒数日
    ├── EventCard.kt             倒数日卡片,主页与日历共用
    ├── SortButton.kt            排序胶囊:选择列表的排序方式
    ├── SearchField.kt           搜索框与范围选择
    ├── EventDetailScreen.kt     单个倒数日的详细画面
    ├── EventEditorScreen.kt     新建 / 编辑(整屏):名字、备注、标签、日期、时间、颜色、批量
    ├── DeleteConfirmDialog.kt   删除前的确认弹窗
    ├── AppearanceScreen.kt      外观与显示:六个主题预设 + 自定义色相
    ├── WidgetSettingsScreen.kt  桌面小组件:面板与清单字号
    ├── NotificationsScreen.kt   通知与提示:提醒设置、每条倒数日的提前量与测试通知
    ├── DataScreen.kt            数据管理:导出、导入、可选加密、导出日历文件
    ├── ChangelogScreen.kt       更新日志,正文取自本仓库的同名文件
    ├── ProjectIntroScreen.kt    项目介绍,正文抽自本文件
    ├── calendar/                手写月历 + 年月选择窗
    ├── components/              选择胶囊、Canvas 图标(含搜索)、色相条、Markdown 渲染、本地化格式
    ├── notify/                  提醒:非精确闹钟的排期、通知接收器、开机后恢复
    ├── widget/                  两个桌面小组件:单条与清单的渲染、接收器、配置界面
    └── theme/                   配色、字体,以及形状与间距的共享 token

倒计时算法、列表排序、搜索匹配、小组件的天数拆分与清单挑选、更新日志解析、备份编解码与加密、 README 抽取与 Markdown 解析都由 app/src/test/ 下的单元测试覆盖,包括月长、闰日、 跨年、两种夏令时切换,以及「今天不算已过去」这个容易差一天的边界。

应用图标

图标预览

矢量 XML 无法绘制汉字,因此启动器文字由 .tools/图标生成/IconGen.java 栅格化: 它加载微软雅黑,把文字缩放到正好落在 Android 自适应图标的 66dp 安全圆内, 再输出 res/drawable-xxxhdpi/ 中的 PNG。

java .tools/图标生成/IconGen.java app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png

隐私

TickCount 只在自己私有的 SharedPreferences 中保存一份倒数日列表——日期、名称、备注、时间、 标签、颜色、置顶和添加时间——此外没有别的东西。颜色是每个倒数日自己的颜色,用来在日历 和列表里区分它们。桌面小组件另有一份 tickcount_widgets,只记录「哪个小组件显示哪一条 倒数日」;主题、排序、语言和小组件外观存在 tickcount_settings。三份都在应用私有目录里,都不会自己 离开设备。

「数据管理」里导出的备份文件写到哪里由你选,加不加密也由你定,应用没有任何办法把它送出去。 它默认不声明任何权限,也不发起网络请求、不含统计与广告;只有可选的「当天提醒」会用到 POST_NOTIFICATIONS(Android 13 起)和 RECEIVE_BOOT_COMPLETED,前者在你打开提醒时才申请, 关掉即撤销。设置页「项目介绍」下面有一个指向本仓库的链接,点「跳转」在浏览器中打开—— TickCount 自己没有联网能力,也没有 INTERNET 权限。 这些数据仅在 Android 自身的云备份开启时才会离开设备,而这由 res/xml/backup_rules.xml 决定。

许可

MIT。

About

[CN]极简、纯离线的安卓倒数日 / 倒计时日历。纪念日、生日、考试的天数倒数,支持桌面小组件、精确到分钟、标签、置顶、搜索排序与自定义主题色。不要任何权限、不联网、无广告、开源。 [EN]A minimal, fully offline countdown calendar for Android. Days until anniversaries, birthdays and exams — home-screen widget, minute precision, tags, pinning, search, sorting and themes. No permissions, no network, no ads. Open source.

Topics

Resources

Stars

9 stars

Watchers

1 watching

Forks

Releases

Contributors

Languages