8aac8c52cc
CI / flutter-gates (push) Successful in 2m41s
- home_page Feed segment 改接 CommunityController:骨架屏首载、空态 CTA、 错误横幅重试、下拉刷新(失败保留旧列表 + SnackBar)、触底游标翻页 (失败态只走显式重试,不随滚动风暴自动重打) - PostCard 三形态(单图通栏 4:3 / 多图折叠封面 +N 角标 / 纯文字 6 行)+ PostMediaGrid(列数规则 + ink 80% scrim 精算)+ LikeButton(error 族修订 Colors.red,T3-14 纯展示禁用态,ToggleSync 接线留 T3-15/16)+ FeedSkeleton (呼吸动效尊重减弱动态设置);降级作者统一「宠友」占位 - SignedNetworkImage:预签名 URL 缓存 key 剥离 X-Amz-* 签名参数, RemoteImage 全仓换用(同图不同签名命中同一缓存条目) - feed 域埋点:feed_viewed 聚合曝光(浏览段开/结算于切 Tab、切分段、 退后台、销毁;≥50% 可见 ≥500ms 段内按帖去重,postId 不上报)+ feed_load_failed(refresh/load_more 双路,会话失效不报) - integration_test/feed_live_test.dart:compose 六容器 Linux 桌面真链路 实测入口(PATBOND_FEED_LIVE=1 门控,默认跳过) - 测试 379 → 421(+42):四态/尾部三态/翻页不丢不重/降级作者/曝光结算 时机/缓存 key/事件属性全覆盖;analyze 0,format 无 diff Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
94 lines
2.9 KiB
Dart
94 lines
2.9 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:patbond_flutter/core/theme/app_theme.dart';
|
||
|
||
/// 点赞 / 收藏按钮语义变体(05 号规范 §3.5:同一组件,图标与语义色
|
||
/// 参数化)。点赞激活 = `error` 图标 + `errorDark` 计数(demo 的
|
||
/// `Colors.red` 3.13:1 修订弃用,D6);收藏激活 = `accentDark` 同色。
|
||
enum LikeButtonVariant {
|
||
like(
|
||
inactiveIcon: Icons.favorite_border,
|
||
activeIcon: Icons.favorite,
|
||
activeIconColor: AppColors.error,
|
||
activeCountColor: AppColors.errorDark,
|
||
),
|
||
bookmark(
|
||
inactiveIcon: Icons.bookmark_border,
|
||
activeIcon: Icons.bookmark,
|
||
activeIconColor: AppColors.accentDark,
|
||
activeCountColor: AppColors.accentDark,
|
||
);
|
||
|
||
const LikeButtonVariant({
|
||
required this.inactiveIcon,
|
||
required this.activeIcon,
|
||
required this.activeIconColor,
|
||
required this.activeCountColor,
|
||
});
|
||
|
||
final IconData inactiveIcon;
|
||
final IconData activeIcon;
|
||
final Color activeIconColor;
|
||
final Color activeCountColor;
|
||
}
|
||
|
||
/// 点赞/收藏交互钮(05 号规范 §3.5 静态规格):图标 20 + 计数 13/w600,
|
||
/// 未激活一律 `inkSoft`(6.59:1)。触控 44×44 由 padding 撑足。
|
||
///
|
||
/// T3-14 只做展示([onPressed] 传 null 即禁用态,仍按正常色渲染计数与
|
||
/// 状态);乐观更新动画与 ToggleSync 接线属 T3-15/16。
|
||
class LikeButton extends StatelessWidget {
|
||
const LikeButton({
|
||
required this.variant,
|
||
required this.active,
|
||
required this.count,
|
||
super.key,
|
||
this.onPressed,
|
||
this.semanticLabel,
|
||
});
|
||
|
||
final LikeButtonVariant variant;
|
||
final bool active;
|
||
final int count;
|
||
final VoidCallback? onPressed;
|
||
final String? semanticLabel;
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final iconColor = active ? variant.activeIconColor : AppColors.inkSoft;
|
||
final countColor = active ? variant.activeCountColor : AppColors.inkSoft;
|
||
return Semantics(
|
||
label: semanticLabel,
|
||
button: onPressed != null,
|
||
child: InkWell(
|
||
onTap: onPressed,
|
||
borderRadius: BorderRadius.circular(AppRadius.pill),
|
||
child: ConstrainedBox(
|
||
constraints: const BoxConstraints(minWidth: 44, minHeight: 44),
|
||
child: Padding(
|
||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||
child: Row(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
Icon(
|
||
active ? variant.activeIcon : variant.inactiveIcon,
|
||
size: 20,
|
||
color: iconColor,
|
||
),
|
||
const SizedBox(width: 4),
|
||
Text(
|
||
'$count',
|
||
style: TextStyle(
|
||
color: countColor,
|
||
fontSize: 13,
|
||
fontWeight: FontWeight.w600,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|