Skip to content

About

安卓小部件速记,样式可自定义,支持webdav备份

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

116 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HelloWidget

一个轻量 Android 应用:文本编辑器 + 桌面小组件。在应用里输入文本,退出后内容以可上下滚动的小部件形式展示在桌面,支持自定义外观,且零后台进程、数据永不损坏。

当前版本:v8.5.1(versionCode 37,compileSdk 36 / minSdk 24 / targetSdk 36)

功能特性

特性 说明
📝 文本编辑 全屏多行编辑器,内容仅在退出 / 返回 / 切后台时保存(不做编辑自动保存)
🧭 顶部导航栏 编辑页顶部一条应用栏,4 个常驻入口一眼可见:设置 / WebDAV 同步 / 立即上传 / 撤回(原先占屏幕底部的两个按钮已上移删除)。导航栏高度固定 56dp,上方那条系统栏(状态栏 / 刘海 / 挖孔)由独立占位条承担高度 —— 系统栏再高也不会挤压标题和按钮(v7.7.1 修复)。顶栏配色与编辑区同色(v8.3.0):底色 = 当前模式下编辑器的背景色、标题与 4 个图标 = 编辑器的文字色,浅色 / 深色模式各用各的那一组,改了编辑器配色顶栏立刻跟着变(此前的固定品牌紫已删除)
↩️ 无限次撤回 顶部「撤回」按钮逐步退回每一次编辑,不设次数上限,直到精确变回刚打开应用时的内容;旋转 / 深色模式重建后撤回历史依然可用;撤回后光标自动落在改动处。v8.4.0 起每条撤回记录压缩成「位置 + 长度 + 被删文本」(不再为每次按键分配对象与两个字符串),长会话内存约降一个数量级,撤回次数仍然不设上限
⬆️ 立即上传 顶部「立即上传」按钮:先把编辑器当前内容落盘,再立刻上传到云端(用户按下的当下意图不会被合并,自己走一趟);未启用/未配置同步时会明确提示去设置,而不是点了没反应
☁️ WebDAV 同步 把最新内容纯单向上传到你自己的 WebDAV(坚果云 / Nextcloud / 群晖 NAS):只依赖本机记录判断内容有没有变,变了就写一个新文件 note<本地时间 yyyyMMdd_HHmmss_SSS>.txt(如 note20261018_192437_123.txt,v8.4.0 起从难读的 unix 时间戳改为可读格式),旧文件永不触碰 —— 云端自动保留每一次上传的历史,也就不需要读取、比对或清理远端。同步期间通知栏有进度条(每次上传都保证可见,最短 1.5 秒),上传成功还会弹一个 Toast;结束立即停止,不留常驻后台。退出瞬间若只是网络抖一下,会在前台窗口内快速重试 2 次(通知显示「网络不稳,正在重试(1/2)…」)而不是等到一分钟后的系统补传(v8.0.3)。设置页的状态 / 诊断块可长按选中复制,也可点「复制全部」一次取全(v8.0.2)
⌨️ 进入即输入 打开应用后光标自动落在第一行行首,并自动弹出输入法,省掉一次点击(读盘完成后触发,不会先弹键盘后填内容)
🌙 自适应深色模式 编辑页随系统深色模式自动切换黑白,切换时自动保存当前内容;小组件颜色不受影响
🪟 可滚动小组件 FrameLayout 根容器 + ListView 集合式小组件:短内容时列表只占文字那么高,文字下方的空白也可点(点击由根容器接管);长内容在小组件内原生上下滚动。v8.5.0 起不再把列表项撑到「宿主报告的小组件高度 − 防误触余量」,那个估算链和滑杆一起删除 —— 底部不可点的死区消失,也不会再出现 v5.8 那种「短内容误滚动半行」。尺寸:默认 4×3(v8.5.1 起旧系统也按同一档折算),可缩放到 2×1(所有 Android 版本支持)
🎨 外观自定义 设置页可调字体大小(10–34sp)、字体颜色、背景颜色、背景透明度;字体大小同时决定编辑器的文字大小(改一处两处同步);并可分别自定义浅色模式 / 深色模式编辑器的背景色与文字色;实时预览即时生效,支持自定义 RGB 取色
🔒 原子写入 内容存储采用 Jetpack DataStore 官方原子写入(临时文件 + fsync + 原子重命名),任意时刻崩溃都不会产生"写一半"的损坏文件
✅ CRC32 校验 文件格式 [UTF-8 内容][4字节 CRC32],读取时校验;发现损坏自动保留现场文件并重建
🪫 零后台占用 无自动保存、无轮询、无常驻服务。小组件数据服务为绑定式,仅桌面渲染时才临时启动;自动上传只跟在「保存内容」之后(退出 / 返回 / 切后台 / 旋转 / 深色模式等所有保存路径),每次保存都立刻尝试、没有任何节流(v8.1.0 删掉了 1 分钟闸门),结束即停前台服务;同一时刻最多一次上传,保存比上传快时后来者自动合并进正在执行的那一趟(一趟上传吸收它开始前积累的所有保存),而要不要真的发请求只由内容哈希决定——内容没变时一个请求都不发;只有失败才有重试间隔。v7.9 起另有一条系统级兜底:保存成功后若上传没能完成,会给系统排一个(固定 id、只会有一个)一次性持久化重试任务,系统在有网络时拉起进程补传,成功即撤销 —— 不轮询、不常驻、首次延迟 30 秒、失败按指数退避,且最多自动重试 5 次(用完就停,不长期驻留)。打开应用只读盘显示内容:不算哈希、不检测、不联网(v8.2.0 起连同「待上传检测」一起删除)
🔇 静默保存 保存成功不弹任何提示(v7.7 起删除全部「已保存」toast);只有写盘失败才提示「保存失败」,旧内容不受影响
💾 备份与换机迁移 走系统的备份通道(v8.2.0 起):allowBackup="true" + 备份规则显式包含 file 与 sharedpref,由 Auto Backup / 厂商换机助手把正文 + 外观配色 + WebDAV 配置(含口令)搬到新设备。代价(刻意接受):WebDAV 口令会随系统备份离机,同步设置页已写明。v8.3.0 删除了 v8.2.0 自加的「导出 / 恢复备份文件」界面 —— 应用里少一块功能就少一处出 bug 的地方(用户要求)
📏 长度上限 内容上限 10,000 字符(v8.4.0 从 100,000 降低:以桌面小部件显示为主,小上限换内存安全),超出时给出可见提示;历史遗留的超长内容完整加载、一个字不丢,但只能删减到上限以下才能继续输入(并给出明确提示)
♿ 无障碍 色板具备可访问名称、选中状态与 48dp 触控目标;滑杆带 labelFor 关联标签;顶部导航栏的图标按钮均带中文可访问名称
🌐 中英双语 默认中文,values-en 提供英文

版本历史

完整更新日志(含每次改动的起因、真机证据与边界)见 CHANGELOG.md。

当前版本:v8.5.1 —— 小组件尺寸契约对齐:

  • 默认大小 4×3 在新旧系统上统一:Android 12+ 本来就按 targetCellWidth=4 / targetCellHeight=3 摆 4×3; Android 11 及以下不读 targetCell,此前用 180dp/100dp 折算出来约 3×2 —— 现在改成 minWidth=250dp / minHeight=180dp (按官方折算表 n 格 ≈ 70n−30dp,即 4 格 / 3 格)。
  • 放开缩放下限:新增 minResizeWidth=110dp / minResizeHeight=40dp(约 2 列 × 1 行)。此前没有声明 minResize*, 下限默认等于 minWidth/minHeight,所以小组件缩不到 2×1/1×1 —— 而 v8.5.0 之后任何尺寸都能正常渲染,这个下限纯属历史值。
  • 只动 widget_info.xml 的 4 个属性值;渲染、数据、同步、权限均无改动。尺寸行为无法在 CI 观测,请你在桌面上拖一下验收。

上一版:v8.5.0 —— 小组件改成「点击交给根容器」,删掉防误触余量:

  1. 小组件根布局从 ListView 换成 FrameLayout:列表高度交给内容(wrap_content),文字下方的空白由根容器接收点击。 「整块可点」不再依赖「把列表项撑到宿主报告的小组件高度 − 余量」这条估算链,于是同时删除: ① 读 OPTION_APPWIDGET_MIN_HEIGHT 算尺寸的逻辑与 setMinimumHeight; ② onAppWidgetOptionsChanged 里的重建 / 重算(缩放改由桌面重新布局,文字自动重排); ③ 设置页的「防误触余量」滑杆与相关文案。 直接结果:底部不可点的死区消失,v5.8「短内容误滚动半行」这类由尺寸取整产生的 bug 从结构上消失。
  2. 行为不变的部分:内容读取与失败三态(空提示 / 读失败提示)、字号与颜色、8dp 内边距、长内容滚动、点击打开编辑页、 无后台常驻、无新增权限、无新增配置入口。数据层与同步完全没有动。
  3. 新增 8 条 Robolectric 用例(WidgetBehaviourTest):钉住「短内容时列表只占文字那么高」「文字下方空白由根容器接住点击」 「长内容仍在组件内滚动且不溢出根容器」「Provider 把点击与背景放在根容器上」「列表项不再被撑高」「工厂无需 widget id」。

上一版:v8.4.0 —— 三件用户点名的改动 + 一轮「失败路径」加固:

  1. 正文上限 100,000 → 10,000 字符(用户决定:以桌面小部件显示为主;撤回次数仍然不设上限)。 历史遗留的超长内容完整加载、不截断,但只能删减到上限以内才能继续输入,并给一次明确提示。 同时撤回记录改成紧凑结构(位置 + 长度 + 被删文本),长会话内存约降一个数量级。
  2. 云端文件名改成可读的本地时间:note20261018_192437_123.txt (前缀 + yyyyMMdd_HHmmss_SSS + 扩展名,精确到毫秒),不再是难读的 unix 时间戳; 旧文件保持原样,不清理不改名。
  3. 失败路径加固(都不改变正常使用行为): ① 读盘失败不再当成「空便签」—— 编辑器保持禁用、所有保存路径拒绝写盘; ② 返回键 / 深色模式切换时写盘失败不再销毁或重建编辑页; ③ 两次保存串行化(旧快照不会覆盖新快照); ④ 同步读盘失败时不再上传空内容; ⑤ CRC 校验失败(内容文件损坏)会在下次打开应用时明确提示一次(并保留损坏现场文件)。
  4. 顺带:内容没变时不再重写磁盘(每次失焦都整份写盘的浪费),上传触发与「保存即上传」语义不变。

更早:v8.3.0 —— 删除 v8.2.0 自加的「导出 / 恢复备份文件」整块功能(系统备份/换机迁移通道保留), 顶栏从固定品牌紫改为与编辑区同色(底色 = 编辑器背景色、标题与图标 = 编辑器文字色,浅色/深色各用一组)。

v8.1.0 —— 每次保存都立刻尝试上传,不再有 1 分钟节流;同一时刻最多一次上传, 突发保存自动合并(一趟上传吸收它开始前积累的所有保存);只有失败才产生重试间隔(前台窗口内 1 秒 / 3 秒, 之后交给系统兜底任务指数退避,最多 5 次)。防重复上传靠的是内容哈希:内容没变时一个请求都不发。

云编译(GitHub Actions)

推送 main 分支或手动触发工作流,自动完成:

  1. 质量门禁:Android Lint + JVM 单元测试(Robolectric),任一失败即中止
  2. 编译 Debug + Release(Release 使用 secrets 中的 keystore 签名)
  3. 仪器化测试:在 CI 的 Android 35 / 36 双档模拟器(KVM 硬件加速)上运行 androidTest。除了「自动弹出输入法」这类只能在真实 Android 运行环境观察的行为,还会在 runner 上启动仓库自带的零依赖 WebDAV 服务器(.github/scripts/webdav_stub_server.py,模拟器经 10.0.2.2 访问),端到端验证上传、「内容没变则零请求」与补传,并把服务器请求日志打印到 Actions 日志里作为证据
  4. 上传构建产物(Actions 页面 Artifacts)
  5. 自动发布 GitHub Release(仅 main 分支,且前三步全部通过),附签名 APK,可直接下载:
https://github.com/llllllllqq/hellowidget/releases/latest

触发方式

  • 自动:推送 main 分支(会发版);推送 qa/** 分支(只跑质量门禁与构建,不发版)
  • 手动:仓库 Actions 页 → Build & Release → Run workflow

所需 Secrets

Release 签名使用以下仓库 Secrets(已配置)。没有 secrets 时(例如 fork 的 PR)流程不会失败,只是产出未签名的 release 包:

Secret 说明
KEYSTORE_BASE64 签名 keystore 文件的 Base64
KEYSTORE_PASSWORD keystore 密码
KEY_ALIAS 密钥别名
KEY_PASSWORD 密钥密码

发新版流程

只改 gradle.properties 两行,提交并推送 main:

hellowidget.versionName=8.5.1
hellowidget.versionCode=37

CI 会自动用 versionName 生成 tag(v8.5.1)与 Release 标题,APK 元数据也取自同一处,三者不会再漂移。 发布后请顺手在 CHANGELOG.md 顶部补一条本版记录(起因、改动、证据、边界)。

本地构建

# 需要 Android SDK(把 sdk.dir 写入 local.properties,该文件已被 gitignore)
./gradlew assembleDebug     # Debug APK
./gradlew assembleRelease   # Release APK

# 签名 Release 需要以下环境变量;不设置时产出未签名包(不会构建失败)
export HELLOWIDGET_KEYSTORE=/path/to/hello-release.keystore
export KEYSTORE_PASSWORD=... KEY_ALIAS=... KEY_PASSWORD=...

# 质量门禁(与 CI 完全一致)
./gradlew :app:lintDebug :app:testDebugUnitTest

# 仪器化测试(需要已连接的设备或模拟器;CI 上由 GitHub Actions 自动跑)
./gradlew :app:connectedDebugAndroidTest

Gradle 版本由仓库内的 wrapper 固定(gradle/wrapper/gradle-wrapper.properties → 9.6.0),无需本机安装 Gradle。

项目结构

hellowidget/
├── CHANGELOG.md                    # 完整更新日志(每次改动的起因、真机证据与边界)
├── .github/workflows/build.yml    # CI:质量门禁 + 构建 + 仪器化测试 + 发布 Release
├── .github/scripts/webdav_stub_server.py  # CI 用的零依赖 WebDAV 测试服务器
├── .github/scripts/release_smoke.sh       # CI 用的 release 包冒烟(装进模拟器启动一次)
├── gradlew / gradle/wrapper/      # Gradle wrapper(版本锁定 9.6.0)
├── app/
│   ├── build.gradle.kts           # 构建配置(compileSdk 36 / minSdk 24 / targetSdk 36)
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/moe/hellowidget/
│       │   │   ├── MainActivity.kt        # 编辑器 + 顶部导航栏(设置/WebDAV/立即上传/撤回)+ 保存流程
│       │   │   ├── UndoHistory.kt         # 无限次撤回:记录每一步文本变更并反向套用
│       │   │   ├── UndoHistoryViewModel.kt# 让撤回历史跨配置变更(旋转/深色模式重建)存活
│       │   │   ├── SettingsActivity.kt    # 设置页(小组件外观 + 编辑器浅/深色配色)
│       │   │   ├── SyncActivity.kt        # WebDAV 同步设置页(凭据/状态/证书指纹)
│       │   │   ├── SyncService.kt         # 同步前台服务(API 34+ 用 shortService,含通知栏进度条)
│       │   │   ├── SyncRetryJobService.kt # 系统级兜底重试任务(JobScheduler 拉起,不显示通知)
│       │   │   ├── sync/                  # 同步核心
│       │   │   │   ├── SyncEngine.kt          # 决策核心:内容哈希决定要不要发请求(纯函数,可单测)
│       │   │   │   ├── OkHttpWebDavClient.kt  # OkHttp 5.4:全流程超时 + 可取消 + TOFU 证书固定
│       │   │   │   ├── TlsPinning.kt          # 证书指纹校验(TOFU,只增不减)
│       │   │   │   ├── SyncManager.kt         # 编排:单飞 + 合并、上传、状态流
│       │   │   │   ├── SyncSettings.kt        # 同步配置与状态存取
│       │   │   │   ├── SyncNotifier.kt        # 进度通知与上传成功/失败 Toast
│       │   │   │   ├── SyncConfig.kt          # URL 与文件名(前缀+本地时间+扩展名)校验
│       │   │   │   ├── SyncLauncher.kt        # 统一触发入口(前台服务,失败降级为进程内)
│       │   │   │   ├── SyncRetry.kt           # 失败后的系统级一次性重试任务(排入/撤销/该不该重试)
│       │   │   │   ├── SyncWindowRetry.kt     # 前台窗口内的有限次快速重试策略(1s/3s,最多 2 次)
│       │   │   │   ├── SyncDiagnostics.kt     # 只读诊断:待机分桶 / 待执行任务原因 / 是否加急
│       │   │   │   └── SyncErrorText.kt       # 错误分类 → 本地化文案
│       │   │   ├── EditorSettings.kt      # 编辑器颜色存取
│       │   │   ├── HelloWidgetApp.kt      # Application:初始化 DataStore
│       │   │   ├── ContentStore.kt        # DataStore 原子写入 + CRC32 + 旧数据迁移
│       │   │   ├── TextWidgetProvider.kt  # 小组件 Provider
│       │   │   ├── TextWidgetService.kt   # 绑定式数据服务
│       │   │   └── WidgetSettings.kt      # 小组件外观设置存取
│       │   └── res/                       # 布局、字符串(中/英)、主题、图标
│       ├── test/                          # JVM 单元测试(Robolectric,云端运行)
│       └── androidTest/                   # 仪器化测试(CI 模拟器上运行)
├── build.gradle.kts               # 根构建配置(AGP 9.4.1 + AGP 内置 Kotlin)
├── gradle.properties              # 全局配置 + 版本号唯一来源
└── settings.gradle.kts

WebDAV 同步使用说明

在应用顶部导航栏点「WebDAV 同步」(云朵图标),填写服务器目录地址、文件名、用户名与口令,打开开关后保存。日常上传不必进这一页:编辑页顶部的「立即上传」按钮随时可用。

服务 目录地址示例
坚果云 https://dav.jianguoyun.com/dav/你的目录/(需在「账户信息 → 安全选项」生成应用密码)
Nextcloud https://你的域名/remote.php/dav/files/用户名/目录/
群晖 / NAS http://192.168.1.5:5005/dav/目录/(明文 http 会显示风险提示)

行为约定:

  • 纯单向上传,且每次都是新文件:本机内容一变,下一次同步就往目录里写一个 note<本地时间 yyyyMMdd_HHmmss_SSS>.txt;旧文件永远不会被覆盖或删除,云端自动保留全部历史。本机没变则一个请求都不发(省流量、省服务器配额)
  • 不读云端:客户端接口里根本没有读取方法 —— 不列目录、不下载、不比对,也不清理旧数据;没有冲突与冲突副本。历史文件多起来不需要本应用操心
  • 文件名:<前缀><yyyyMMdd_HHmmss_SSS><扩展名>(本地时间、精确到毫秒),前缀与扩展名来自「文件名」字段(默认 note.txt → note20261018_192437_123.txt);同一毫秒内的第二次上传会 +1 毫秒避免撞名,时钟回拨也不会重名(v8.3.0 及更早的旧文件仍是裸 unix 名字,保持原样)
  • 目标目录不存在时会自动创建(服务器回 409/404 时补一次 MKCOL 再重试上传)
  • 上传时机(v8.1.0):只有「保存内容」才触发自动上传(退出 / 返回、切后台,以及旋转、切换深色模式等触发的自动保存),而每次保存都立刻尝试,没有任何节流;要不要真的发请求只由内容有没有变化决定(内容没变则一个请求都不发,这是防重复上传的唯一机制)。同一时刻最多一次上传,保存比上传快时后来者会合并进正在执行的那一趟(一趟上传吸收它开始前积累的所有保存,且绝不并发 PUT)。只有失败才产生重试间隔:前台窗口内 1 秒 / 3 秒各一次,窗口里没救回来就交给系统兜底任务(首次 30 秒,之后 60 秒起指数退避,最多 5 次)。打开应用不上传也不检测(v8.2.0 起连"顺手算一次哈希"的橙点检测也删了):只把磁盘内容显示出来
  • 通知与结果提示:Android 13+ 需要通知权限才能看到进度条;拒绝权限时同步照常工作。每次确实发生上传时,进度通知至少显示 1.5 秒;上传成功弹 Toast「已上传到云端」,上传失败也弹 Toast(v7.8 起失败不再往通知栏留东西,完整原因仍记在同步设置页的「同步状态」里)
  • 上传失败会自动补传(v7.9):写盘成功后立刻给系统排一个一次性持久化任务(JobScheduler,需要网络、按指数退避、进程被杀或重启后依然在),上传成功即撤销;因此「保存了却没上传」最多只是一次延迟,不再需要清后台。(v8.0.1 试过把它改成「加急」以获得绕过待机分桶网络限制的收益,但平台明确禁止「加急 + 延迟」,而立刻执行会抢走前台服务的可见上传,故保持常规 + 延迟;v8.1.0 起首次延迟从 65 秒缩短为 30 秒 —— 65 秒当初只为躲开已删除的 1 分钟闸门,现在的下界只是"别和前台窗口抢锁"。)v8.0.3 起多了一层更早的兜底:退出瞬间若是暂时性失败且失败得很早,会先在已经亮着通知的前台窗口里退避重试 2 次(1 秒、3 秒,通知正文显示「网络不稳,正在重试(1/2)…」),成功就当场看到「已上传到云端」;窗口里没救回来才落到上面那条系统任务。同步设置页会显示「自动重试:已排队(预计 HH:MM:SS 补传)/ 无」、「上次访问云端」与「系统诊断(待机分桶 / 待执行任务原因 / 是否加急)」供排查。只有看起来是暂时性的失败才自动重试(网络 / 超时 / IO / 5xx / 目录缺失 / 锁定 / 配额),凭据错误、证书不受信这类需要你先处理的问题不会反复重试
  • 网络请求全程有超时(v7.9):单次同步的上限是 60 秒(覆盖 DNS → 建连 → 写正文 → 读响应),任何一次卡住都不会让后续同步被无限期挡住 —— 旧版没有写超时,一条半开连接就能造成「只能清后台」
  • 坚果云:坚果云对「父目录不存在」「目录已存在」「读不存在的文件」都返回非标准的 409,客户端已逐条兼容并降级处理(见 V7.5_ONE_WAY_UPLOAD_REPORT.md、V7.4_NUTSTORE_409_REPORT.md)
  • 自签名证书:https 握手失败时同步页会显示证书指纹,点击「信任并记住」后按该指纹固定校验;指纹变化会再次要求确认(不会无条件信任所有证书)

数据存储说明

  • 用户内容:filesDir/user_content.dat(DataStore 格式:[UTF-8 内容][CRC32];上限 10,000 字符)
  • 外观设置:SharedPreferences hello_prefs(字体大小/颜色/背景等,非关键数据)
  • 损坏恢复:CRC 校验失败时保留现场文件 corrupt_<时间戳>.dat(只保留最近 3 份)并重建,应用始终可用;v8.4.0 起会在下次打开应用时明确提示一次(损坏可能发生在小组件/后台进程的首次读取里,用户当时不在编辑页)
  • 读盘失败(v8.4.0):读失败与「空便签」严格区分 —— 读不出来时编辑器保持禁用、所有保存路径拒绝写盘,绝不用空内容覆盖磁盘上唯一那份内容
  • 备份与迁移(v8.2.0):allowBackup="true",且 backup_rules.xml / data_extraction_rules.xml 显式包含 file 与 sharedpref 两个域 —— 云备份与设备间迁移都能带走 filesDir/user_content.dat 与 hello_prefs。规则里写的是 include 而不是"什么都不写",因为它就是"到底备份了什么"的可审计清单
  • 同步凭据:WebDAV 地址/用户名/口令同样存在 hello_prefs(因此也会随系统备份一起离机,这是 v8.2.0 的刻意取舍:数据安全优先于隐私);建议使用服务端的「应用专用密码」。开启同步后,笔记内容会按你的设置上传到你自己的 WebDAV 服务器(服务端保存的是明文文本)

开源许可证

本项目基于 MIT License 开源,任何人可自由使用、修改、分发(含商用),仅需保留版权声明与许可证文本,详见 LICENSE。

第三方组件声明(含应用图标出处)见 THIRD_PARTY_NOTICES.md。

About

安卓小部件速记,样式可自定义,支持webdav备份

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages