Skip to content

feat: 桌面小组件扩展 —— 6 类内容 × 小/中/大(图片渲染架构)#406

Open
TNT-Likely wants to merge 29 commits into
mainfrom
feat/home-widget-expansion
Open

feat: 桌面小组件扩展 —— 6 类内容 × 小/中/大(图片渲染架构)#406
TNT-Likely wants to merge 29 commits into
mainfrom
feat/home-widget-expansion

Conversation

@TNT-Likely

Copy link
Copy Markdown
Owner

桌面小组件扩展 —— 6 类内容 × 小/中/大(图片渲染架构)

现有 home_widget 图片渲染架构上,把桌面小组件从「1 个中号收支速览」扩展到 6 类内容 × 多尺寸;不上纯原生。现有组件完整保留(存量桌面放置不失效)。

做了什么

  • home_widget 0.7 → 0.9.2(0.9.3 要求 Flutter ≥3.38 超项目锁定的 3.27,0.9.2 已含 getInstalledWidgets / 可配置能力)。
  • 参数化渲染管线:HWType/HWSize/WidgetSpec;updateAllWidgetsgetInstalledWidgets 只渲已安装的组件(省开销 / 友好 iOS 30MB 进程限);拿不到列表退化默认集。
  • 6 类 view × 各尺寸:收支速览 / 净资产(趋势线+资产负债+账户明细)/ 快速记账(分类快捷格)/ 预算(环形+进度条)/ 最近交易 / 综合仪表盘。全部 headless 参数化(颜色/主题/明暗/文案显式入参),多币种折算复用 rate_math,净资产排除隐藏账户(与账户隐藏特性联动)。
  • 深链扩展:new?type=&category=(点分类预填记账页)、open?page=assets|budget|detail(净资产/预算/最近交易落地页)。
  • i18n 三语 + headless locale 解析(resolveWidgetLocalizationslanguageProvider)。
  • 管理页升级为组件库:复用真实 view 的 6 卡预览画廊 + 添加引导;对齐 SectionCard/BeeColorTokens/.scaled() 规范。
  • 原生壳:iOS 5 个新 WidgetKit widget + Android 5 个新 AppWidgetProvider。

D2:现有组件完整保留

现有中号收支速览的 iOS kind BeeCountWidget / Android provider 类名 / 图 key widgetImage 全部不变——它只是并入统一渲染管线,原生壳零改动,存量用户桌面已放置的组件 100% 继续工作。新组件用各自 kind/provider 并列新增。

验证状态(两半分清楚)

  • ✅ Dart 侧(已验证):flutter analyze 0 error;flutter test 478 passed(1 个 bill_creation_service_test 失败是 main 上就有的预置项,与本 PR 无关)。含 ~97 个 widget 测试(极端数据防 RenderFlex 溢出、多币种折算断言、Android 多尺寸匹配等)。
  • ⚠️ 原生壳(需真机验收):iOS Swift × 6 + Android Kotlin/XML × ~20 未经 Xcode/gradle 编译或真机验证(作者环境无 iOS/Android 构建能力),均照现有 BeeCountWidget.swift / BeeCountWidgetProvider.kt 模板结构复制改造。

验收 checklist(真机)

  • Xcode Product ▸ Build(新 .swift 因 Xcode16 同步文件夹机制应自动纳入 BeeCountWidgetExtension target,请核对左侧文件不是灰色未纳入)。
  • Android gradle sync/build。
  • 真机分别添加 5 类新组件 × 各尺寸,验显示 / 缩放 / 点击深链跳转。
  • 存量验证:升级后原有中号收支速览组件仍正常刷新、不丢。
  • iOS26 Liquid Glass 外观下静态图观感。

已知限制(见代码注释 + .docs/home-widget/)

  1. Android 尺寸 dp 阈值为近似值,建议真机(尤其 ColorOS)校准。(注:已避开 PR fix(widget): remove targetCellWidth/Height for ColorOS 5-grid compatibility #307 移除过的 targetCellWidth/Height ColorOS 雷。)
  2. glance 小号在 Android 无独立 provider(安卓沿用旧 medium-only provider)。
  3. 点击区为整块跳转;按分区 / 按具体分类深链是后续细化(注释标 TODO)。
  4. 组件内即时记账未做(图片架构后台无法重新出图,dart:ui 限制;属「决策二 / 混合」范畴,列二期)。
  5. resolveWidgetLocalizations 只看系统单一首选 locale(非完整多候选算法)。

说明

  • 纯 App 侧改动,无 Cloud 依赖。
  • 设计/调研/计划文档在 .docs/home-widget/(.docs 已 gitignore,不入 PR)。
  • 等真机验收通过后再合并。

pub.dev 最新 0.9.3 要求 Dart >=3.10.0/Flutter >=3.38.1,超出项目当前锁定的
Flutter 3.27.3/Dart 3.6.1,会导致 pub get 解析失败;其相对 0.9.2+1 唯一变化
是 iOS UIScene Lifecycle 支持,与本阶段无关,故锁定兼容当前工具链的 0.9.2+1。
新增 WidgetSpec 目录模型(6 类型×合法尺寸,imageKey 映射,glance-medium 按
D2 back-compat 沿用旧 key widgetImage);WidgetManager.updateWidget 重构为
updateAllWidgets,按 HomeWidget.getInstalledWidgets() 只渲染已安装的组件,
拿不到列表时退化为默认集(至少 glance-medium);现有今日/本月收支取数迁入
WidgetDataService.gatherGlance;渲染 pixelRatio 4.0→3.0 更省内存;print 全
部换 logger。其余类型(netWorth/quickAdd/budget/recent/dashboard)的取数与
视图留给 Phase B。

spec 选择逻辑(selectSpecsToRender/matchInstalledSpecs)与 imageKey 映射均
为纯函数,补充单测覆盖。
顶部文件级注释后补 library; 声明,去掉 widget_spec_test.dart 里未使用的
material.dart 导入。
为桌面小组件「最近交易」类型取数用:按 happenedAt 降序取前 limit 笔,
不做 exclude 过滤,不含分类/账户 join(与 getRecentTransactionsWithCategory
的共享账本 hydration 语义区分)。
WidgetDataService 新增 5 类内容的 gather 方法(净资产总览/趋势/账户明细、
快速记账常用分类、预算总览、最近交易、综合仪表盘组合),复用现有 repo
方法与 App 的多币种折算口径(services/currency/rate_math.dart 的
mergeEffectiveRates/computeConvertedNetWorth),headless 版本直接读 repo
不依赖 Riverpod ref。净资产系列对缺有效汇率的币种整条剔除,与资产页
convertedNetWorthProvider 同口径。全部方法配内存库单测,含多币种折算断言。
updateAllWidgets/_renderSpec 新增 baseCurrency 参数(默认 CNY,兼容现有
调用方);非 glance-medium 的 spec 改为按 type 分派到对应
WidgetDataService.gather*,验证取数链路可用,仍跳过实际渲染(无 View,
留给 Phase B2)。
- 新增 lib/widget/views/widget_view_style.dart:小组件 headless 视图共用的
  色值/字重(支出#E5533C、收入#2FA36B、明暗卡片背景等),避免各 View 各写一份
- 新增 GlanceView:medium 从旧 HomeWidgetView 原样迁移(视觉不退化),small
  为新增 155x155 紧凑卡(今日支出大数 + 本月收支底栏)
- widget_manager.dart 拆分 _renderSpec 为按类型分派,glance(小/中)接入真实
  渲染;netWorth/quickAdd/budget/recent/dashboard 仍只取数不渲染(留后续
  阶段);新增 dark 参数(取自 PlatformDispatcher,渲染批次内共用一次)
- home_widget_view.dart 保留不动(widget_management_page.dart 预览页仍在用)
- 净资产大数 + 环比 chip(取趋势序列首尾两点,近似当前 vs 一个月前)+
  CustomPainter 手绘 sparkline(large 带面积渐变填充);中/大加资产/负债
  进度条(占比按两者较大值折算);large 额外展示 top 4 账户明细,未折算的
  账户按原币兜底展示(不误用 baseCurrency 符号)
- 资产=收入语义色、负债=支出语义色,复用 accounts_page.dart 里
  BeeTokens.expenseColor 给总负债着色的既有约定,不是独立发明的红绿方案
- widget_manager.dart 新增 _renderNetWorth,netWorth 从"只取数不渲染"
  移除,budget/quickAdd/recent/dashboard 仍跳过
- 修复过程中发现固定死高 SizedBox 包 hero 区在真实字体行高下会
  RenderFlex 溢出,改为自然高度排列 + Expanded/ScrollView 兜底可变区域
- small:2x2 网格 = 前 3 个常用支出分类(icon+名称) + 记一笔(honey 底 + 按钮)
- medium:一整行最多 4 个分类 + 记一笔
- 分类图标优先按 CategoryService 已知 key 渲染 Material 图标,启发式识别
  emoji 字符串时直接以文字展示,两者都拿不到时 CategoryService 自身已兜底
  Icons.category
- widget_manager.dart 新增 _renderQuickAdd,quickAdd 从"只取数不渲染"移除,
  budget/recent/dashboard 仍跳过(留 Phase B2b)
- app.dart / main.dart / theme_providers.dart(x2) / ledgers_page_new.dart
  统一补上 ref.read(baseCurrencyProvider),不再让 NetWorthView 折算永远
  兜底 CNY
- widget_provider.dart(唯一有 l10n 的调用点)顺带把 accountTotalBalance/
  totalAssets/totalLiabilities 三个已有 arb key 传给 netWorthLabel/
  totalAssetsLabel/totalLiabilitiesLabel,其余调用点沿用 WidgetManager
  默认中文兜底(与 appName 等既有参数同一套约定)
- small:环形进度(CustomPainter)+ 中心大字 xx%/已用 + 底部剩余/总额
- medium:总额/已用/百分比头部 + 粗进度条 + 分类用量 top3 小卡
- 用量状态(normal/warning/danger/exceeded)决定弧/条颜色
- 无总预算时优雅降级为占位文案,不与分类预算存在与否绑死
- WidgetDataService 新增 gatherLedgerCurrency(账本自身币种,供预算/
  最近交易格式化用,区别于净资产系列的全局本位币 baseCurrency)
- widget_manager 接管线:budget 从 _gatherAndSkip 挪出,新增 _renderBudget
- 每行:分类/转账图标 + 名称(分类名;转账为账户→账户,均缺兜底"未分类")
  + 次行(账户/分类 · 时间,今天显示时:分,更早显示月/日) + 右侧金额
  (支出负/红、收入正/绿、转账中性;币种取交易自身,缺失兜底账本币种)
- 单行组件 RecentTransactionRow 公开导出,供后续 dashboard 视图直接复用
- medium 最近 3 笔,large 最近 6 笔;空列表兜底"暂无交易"
- widget_view_style 新增共享 widgetLooksLikeEmoji/widgetCategoryIcon
  (与 QuickAddView 私有实现同算法,供 recent/dashboard 复用)
- widget_manager 接管线:recent 从 _gatherAndSkip 挪出,新增 _renderRecent
- 一屏四区:顶部本月支出/收入 → 净值趋势 sparkline(面积渐变)→
  "最近交易"标签 + 最近 2 笔 → 底部快捷记账行(前 3 分类 + 记一笔)
- 趋势 sparkline 复用 NetWorthView 同款画法(新增公开 WidgetSparkline
  共享实现,NetWorthView 自身私有实现不动,避免触碰已测试文件)
- 最近交易区块直接复用 RecentView 导出的 RecentTransactionRow
- 变长区块(趋势图/最近交易列表)用 Expanded 吸收剩余空间,不写死高度,
  防 382pt 高度下的 RenderFlex 溢出
- widget_manager 接管线:dashboard 从 _gatherAndSkip 挪出,新增
  _renderDashboard;_gatherAndSkip 已无调用点,整体删除
- 至此 HWType 全部 6 种内容类型均已接入真实渲染,Phase B2b 完成
新增 widgetToday/widgetQuickAddLabel/widgetBudgetTotal/widgetBudgetRemaining/
widgetNoBudget/widgetNoTransactions/widgetRecentTransactions/widgetNoAccounts
等 arb key(zh/zh_TW/en,韩语按惯例兜底英文),预算/未分类等复用已有 key。

WidgetManager 新增 resolveWidgetLocalizations + updateAllWidgetsLocalized,
供 main.dart/theme_providers.dart/ledgers_page_new.dart 等无 BuildContext
的调用点按 languageProvider 还原 locale 后取值;widget_provider.dart 的
updateAppWidget(有真实 context)同步补全全部文案参数。app.dart 前台恢复的
调用点本次未接入(范围外),仍显示中文默认值。

顺手补上 registerInteractivityCallback 空回调的日志记录。
widget_management_page.dart 从单一收支速览预览升级为收支速览/净资产/快速
记账/预算/最近交易/综合仪表盘 6 张预览卡,每卡直接复用对应的真实 headless
View(GlanceView/NetWorthView/QuickAddView/BudgetView/RecentView/
DashboardView)+ 按各 View 冒烟测试同款手法造的示例数据,按代表尺寸(中/大号)
渲染,让用户添加组件前先看到实际效果。保留 iOS/Android 添加指引与快捷记账
说明。

页面结构改用 PrimaryHeader + SectionCard + BeeTokens + .scaled(),移除裸
Theme/Card 用法;新增 14 个画廊文案 arb key(zh/zh_TW/en,韩语兜底英文)。
BeeCountNetWorthWidget / BeeCountQuickAddWidget / BeeCountBudgetWidget /
BeeCountRecentWidget / BeeCountDashboardWidget,均照 BeeCountWidget.swift
模板复制:TimelineProvider 按 widgetFamily 读对应 widget_<type>_<size>
图片、StaticConfiguration + containerBackground(.clear) +
contentMarginsDisabled、整块 Link 深链(第一版不分区,TODO 标注后续细化)。
BeeCountWidgetBundle 注册全部 6 个 widget,现有 BeeCountWidget.swift 不动。
netWorth/quickAdd/budget/recent/dashboard 各 spec 补 iosKind + iosFamily,
与 ios/BeeCountWidget/ 下对应新 WidgetKit 壳的 kind/supportedFamilies 一一
对应,使 matchInstalled 能识别用户已安装的新组件、渲染管线据此出图(逻辑
本身不改,仅补数据)。
BeeCountNetWorthWidgetProvider 按 getAppWidgetOptions 实际尺寸选图片 key,
整块点击深链资产页,照 BeeCountWidgetProvider 模板结构复制改造。
BeeCountQuickAddWidgetProvider 按尺寸选图片 key,整块点击深链新建支出,
照 BeeCountWidgetProvider 模板结构复制改造。
BeeCountBudgetWidgetProvider 按尺寸选图片 key,整块点击深链预算页,
照 BeeCountWidgetProvider 模板结构复制改造。
BeeCountRecentWidgetProvider 按高度选图片 key(两档宽度相同),整块点击
深链明细页,照 BeeCountWidgetProvider 模板结构复制改造。
BeeCountDashboardWidgetProvider 单一尺寸,固定读 widget_dashboard_large,
整块点击深链明细页,照 BeeCountWidgetProvider 模板结构复制改造。
netWorth/quickAdd/budget/recent/dashboard 共 10 个新 spec 补
androidClassName,对应 Phase E 新增的 5 个 AppWidgetProvider;并在
androidClassName 字段文档记录已知局限——matchInstalled 按类名匹配、
不感知尺寸,同一 provider 类名多尺寸时目前只会匹配到目录里最前的那档。
本仓 #307(cf5daf2)已验证 targetCellWidth/Height(API31+)在 ColorOS
(一加/OPPO/realme)启动器上会导致占用单元格数算错、桌面小部件被压缩,
当时移除后回退用 minWidth/minHeight 自动算。这 5 个新 provider 之前误加了
同一属性,补上同样的规避;minWidth/minHeight/maxResizeWidth/Height 不受
该问题影响,保留。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant