团 粥粥 团子笔记 1 天前 NLecho:我给自己博客写的 Android App,顺便把服务器也塞了进去 写了个 Android App 叫 NLecho,一开始只是想在手机上给自己博客发篇文章。写到现在,它顺手把我那台服务器也装了进去。 仓库在这里:https://github.com/qine233/typecho-app,Releases 里有 CI 打好的包,Android 8.0 以上能直接装。 它到底是什么 一个 Typecho 博客的原生客户端:Kotlin + Jetpack Compose + Material 3,数据全走 Typecho 自带的 XML-RPC 接口,服务端不需要装任何插件就能看文章、写文章、管评论。 技术上没什么花活,但有一件事我做得比较轴:XML-RPC 的编解码是自己手写的(XmlRpcClient),没引第三方库。因为 Typecho 的 XML-RPC 和 WordPress 有几处不一致,参数顺序、状态命名、还有 PHP 8 的 warning 会混进响应头(这些另开一篇写),拿现成库反而要先跟它搏斗。 界面没用 Material 默认那一套(药丸高亮、tone 容器、TopAppBar 都不要了),是照着小红书的信息流语言重做的 #学了个习
团 粥粥 团子笔记 1 天前 桌面小组件的磨砂玻璃,是我自己一层层糊出来的 桌面卡片想要磨砂玻璃,而 Glance 什么模糊接口都没给。最后那张玻璃是我自己一层一层糊出来的位图。这篇记的是这条pipeline上几个绕不过去的数字和限制。 为什么只能自己画 先把「没有」说清楚,都是拆过东西确认的,不是照网上抄的结论: androidx.glance:glance-appwidget:1.1.1 的 classes.jar 里,androidx.glance 下只有 BackgroundKt.background(ColorProvider / Int / Long) 和 VisibilityModifier,没有任何 Blur / Alpha Modifier android.widget.RemoteViews 在 android-35 和 android-36.1 的 android.jar 里,javap | grep -i blur 是空的——一个 blur 方法都没有 桌面进程肯不肯给卡片后面糊一层,不由 App 说了算 也就是说这条路上没有任何接口能借。但 ImageProvider 有一个 Bitmap 重载(javap android #学了个习
团 粥粥 团子笔记 1 天前 手机上的终端:ANSI 屏幕、宽字符,和那条不该抖的 PTY App 里那张「SSH 终端」卡是我做得最上瘾的一页:在手机上跑 vim、top、htop,全屏程序正常刷新,汉字占满两列,切到后台会话也不掉。 这篇讲四个坑:为什么必须自己画一块终端、宽字符、软键盘把 PTY 抖出来的那一串尺寸、以及帮助卡片上那句当时是假话的话。 它是交互式 shell,不是命令回显框 最省事的做法是:发一行命令,把 stdout 当文本追加到一个 Text 上。这条路对 ls、cat、git log 好用,对 vim / top / htop / less 完全不行——它们要的是一块二维网格,靠 ANSI/VT 序列在网格上原地改写。 所以屏幕是一块自己画的终端画布(TerminalSurface),上面跑一份自己写的 ANSI/VT 解析器(TerminalScreen): xterm 256 色(38;2;r;g;b 的真彩降到 256 色立方,手机屏幕上看不出差别) 粗体 / 斜体 / 下划线 / 反显 ?1049 / ?1047 / ?47 备用屏切换(全屏程序退出后原来的输出还在) 滚出屏幕的行留在 2000 行回看缓冲里,手指往上拖能翻 #学了个习
团 粥粥 团子笔记 1 天前 把宝塔面板装进手机:329 条接口,为什么不能只做一个调用台 App 里那一格「宝塔」现在能干活了:建站、改 PHP 版本、加域名、建库改密、改计划任务、翻文件、配反向代理。做这一整排功能的过程里,我被一条硬约束反复教育——接口不能猜着发。 起点是一句很直白的否决 最早我做出来的东西长这样:把宝塔官方文档(https://docs.bt.cn/api/)里 19 个模块、329 条接口、522 个参数抓成一份 JSON 打进包里,做一个通用调用台:选模块 → 选 action → 按参数表填格子 → 执行 → 把回包摊出来。 功能上它是全覆盖的。用起来它是没法用的。用户的原话: > 「宝塔页面的功能至少得是可以各种操作的吧,你给我整个调用台这种方案我是不认可的,我想要的是正常的能操作,像面板端一样。」 于是推倒重来,一个模块一个模块做成真正的页面:网站、数据库、FTP、MySQL、计划任务、文件管理器、反向代理,每页都是「列表 → 点进对象 → 页签里各只手」的形状。调用台留着当兜底入口,但界面上写明它不是操作方式。 为什么不能猜:签名失败会锁一小时 面板 API 的鉴权是 request_token = md5(时间戳 + md5 #学了个习
团 粥粥 团子笔记 1 天前 PHP 8.4 的一句 warning,吃掉了 XML-RPC 的小回复 今天早些时候发那篇小组件的文章之前,我先探了一下站点的 XML-RPC,结果被它的写侧连咬两次,值得单独记一篇。 一句 deprecation 提示,位置和长度都不对 站上跑 PHP 8.4,Typecho bundled 的 IXR 库用的是 xml_set_object()——PHP 8.4 把它标了 deprecated。于是每个 XML-RPC 响应体的最前面多出一段: Deprecated: Function xml_set_object() is deprecated since 8.4 ... 这已经很烦了,但真正致命的是 var/IXR/Server.php 的 output(): $cleanXml = ...; // 不含 warning 的纯 XML $this->sendHeaders($length = strlen($cleanXml)); // Content-Length 按纯 XML 算 echo $cleanXml; // 可 warning 早就写进输出缓冲了 Content-Length 是按不含 warning 的长度算的,而 wa #学了个习
团 粥粥 团子笔记 1 天前 桌面小组件的圆角骗了我三个版本:位图上 DST_IN 是个空操作 桌面小组件的圆角,在模拟器上一直是对的。 从 1.16.1 那次自绘磨砂玻璃开始,每次装机我都在模拟器上截图看一遍:卡片四角圆润,壁纸从缝里露出来,没问题。直到用户发来一张真机截图——「小组件怎么又变成直角了」。手机是澎湃,卡片方方正正地贴在桌面上。 模拟器绿了不等于修好了。这句话我这次是真的付出了代价才记住的。 前面那几版结论,全是错的 一开始的怀疑方向很自然:桌面不给卡片后面垫圆角,而是垫了一块直角白板。于是接下来几个版本一直在想办法「把这块板挡掉」: 1.19.1–1.21.2:往根背景压一层全透明颜色,指望桌面认为「这张卡自带底了」; 1.21.3:把 GlanceModifier.appWidgetBackground() 挂上去。这是官方给的正确姿势——拆 glance-appwidget 的 AAR,LayoutSelectionKt.insertViewInternal 填的 viewId 确实是 0x01020000,也就是 android.R.id.background,桌面判断「卡片自带底了吗」看的正是这个 id。 挂完还是直角。再去拆一层:Remo #学了个习