Files
pangolin/client/lib/widgets/plan_badge_card.dart
wangjia 3785fdf1c1
ci-pangolin / Lint — shellcheck (push) Successful in 5s
ci-pangolin / OpenAPI Sync Check (push) Successful in 21s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Successful in 6s
ci-pangolin / Flutter — analyze + test (push) Successful in 24s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (push) Successful in 5s
ci-pangolin / Codegen Drift — token 生成物未漂移 (push) Successful in 5s
ci-pangolin / Go — build + test (push) Successful in 10s
ci-pangolin / E2E Smoke — L4 进程级端到端 (push) Successful in 16s
ci-pangolin / Go — integration (mysql/redis testcontainers) (push) Successful in 4m16s
ci-pangolin / Golden — 视觉回归 (components + auth) (push) Successful in 14s
style(client/shell): 会员卡字体调小,有效期完整显示
有效期行被 chevron 挤得截断。套餐名 12→11.5、有效期 10.5→9.5、chevron 15→14、
间距 10→9,让「有效期 YYYY-MM-DD」完整显示。golden 重生成。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 21:06:06 +08:00

83 lines
3.0 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// plan_badge_card.dart — 侧栏底部套餐卡(对照 dapp.jsx 侧栏底部)
//
// surface 底 + border + radius-md;左 30×30 crown 渐变(clay500→700)
// 右两行:套餐名 + 额度/有效期。免费/PRO 两态。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../pangolin_theme.dart';
import '../state/account_providers.dart';
import '../state/app_providers.dart';
import '../state/navigation_provider.dart';
import 'pangolin_icons.dart';
class PlanBadgeCard extends ConsumerWidget {
const PlanBadgeCard({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final c = context.pangolin;
final t = ref.watch(appTextProvider);
final isFree = ref.watch(isFreePlanProvider);
final exp = ref.watch(meProvider).valueOrNull?.expiresAt;
// 「我的」入口:点会员卡进账户页;选中态高亮。
final active = ref.watch(navViewProvider) == NavView.account;
String two(int v) => v.toString().padLeft(2, '0');
final expLine = exp == null
? t.expires
: '${t.expires} ${exp.toLocal().year}-${two(exp.toLocal().month)}-${two(exp.toLocal().day)}';
return Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(PangolinRadius.md),
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: () => ref.read(navViewProvider.notifier).state = NavView.account,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 11, vertical: 9),
decoration: BoxDecoration(
color: active ? c.accentSubtle : c.surface,
border: Border.all(color: active ? c.accent : c.border),
borderRadius: BorderRadius.circular(PangolinRadius.md),
),
child: Row(children: [
Container(
width: 30,
height: 30,
decoration: const BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [PangolinColors.clay500, PangolinColors.clay700],
),
),
child: const Icon(PangolinIcons.crown, size: 15, color: PangolinColors.white),
),
const SizedBox(width: 9),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
isFree ? t.freePlanName : t.proMember,
overflow: TextOverflow.ellipsis,
style: PangolinText.caption.copyWith(color: c.fg1, fontWeight: FontWeight.w600, fontSize: 11.5),
),
Text(
isFree ? t.quotaFree : expLine,
overflow: TextOverflow.ellipsis,
style: PangolinText.caption.copyWith(color: c.fg3, fontSize: 9.5),
),
],
),
),
Icon(PangolinIcons.chevronRight, size: 14, color: c.fg3),
]),
),
),
);
}
}