111 lines
3.7 KiB
Dart
111 lines
3.7 KiB
Dart
import 'package:flutter/material.dart';
|
||
|
||
import '../../../core/i18n/app_locale.dart';
|
||
import '../../../core/theme/tokens.dart';
|
||
import '../home_data.dart';
|
||
import '../home_screen.dart' show formatPop;
|
||
|
||
/// HOME 주간 정보 — 발주사 9/9 검토회신 2항 · HOME 정보위계 v1.0 §2 의 2 · 3 · 6 · 7번(A-37).
|
||
///
|
||
/// 🟡 **배치는 임시다.** 기준 화면 「REFINE v5A · HOME · Default」 를 아직 실측하지 못해(당사 사본에
|
||
/// 없고 원본 파일은 로그인 필요) 정보 위계 v1.0 §7 「프레임 실측과 무관하게 반드시 포함」에 따라
|
||
/// 값만 먼저 싣는다. 자리 · 모양은 해석 확인 요청 영역A Q-A16 회신 또는 실측 후 맞춘다.
|
||
/// 값의 뜻은 [HomeWeekly] — 모르는 값은 0 으로 채우지 않고 「—」.
|
||
class HomeWeeklyCard extends StatelessWidget {
|
||
const HomeWeeklyCard({super.key, required this.weekly});
|
||
|
||
final HomeWeekly weekly;
|
||
|
||
static const _label = TextStyle(
|
||
fontFamily: AppFonts.body,
|
||
fontSize: 13,
|
||
height: 18 / 13,
|
||
color: AppColors.onCosmicVariant,
|
||
);
|
||
static const _value = TextStyle(
|
||
fontFamily: AppFonts.body,
|
||
fontSize: 14,
|
||
fontWeight: FontWeight.w600,
|
||
height: 18 / 14,
|
||
color: AppColors.onCosmic,
|
||
);
|
||
|
||
static String _signed(num v) => '${v >= 0 ? '+' : '−'}${formatPop(v.abs().round())}';
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final l10n = context.l10n;
|
||
final w = weekly;
|
||
final change = w.rankChange;
|
||
Widget row(String label, Widget value) => Padding(
|
||
padding: const EdgeInsets.symmetric(vertical: AppSpace.s2),
|
||
child: Row(
|
||
children: [
|
||
Expanded(child: Text(label, style: _label)),
|
||
value,
|
||
],
|
||
),
|
||
);
|
||
Text text(String s) => Text(s, style: _value);
|
||
|
||
return Container(
|
||
padding: const EdgeInsets.symmetric(
|
||
horizontal: AppSpace.s4,
|
||
vertical: AppSpace.s2,
|
||
),
|
||
decoration: BoxDecoration(
|
||
color: AppColors.cosmicSurfaceContainer,
|
||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||
border: Border.all(color: AppColors.cosmicOutline),
|
||
),
|
||
child: Column(
|
||
children: [
|
||
row(
|
||
l10n.homeWeeklyRank,
|
||
Row(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
text(w.rank == null ? '—' : l10n.homeWeeklyRankValue('${w.rank}')),
|
||
if (change != null && change != 0) ...[
|
||
const SizedBox(width: AppSpace.s1),
|
||
Text(
|
||
'${change > 0 ? '▲' : '▼'}${change.abs()}',
|
||
style: _value.copyWith(
|
||
fontSize: 12,
|
||
color: change > 0
|
||
? AppColors.cosmicAccent
|
||
: AppColors.cosmicBlue,
|
||
),
|
||
),
|
||
],
|
||
],
|
||
),
|
||
),
|
||
// 두 축 각각 — 단일 백분율로 합치지 않는다(§3 4번).
|
||
row(
|
||
l10n.homeWeeklyGrowth,
|
||
text(
|
||
'${w.weekGrowthPop == null ? '—' : _signed(w.weekGrowthPop!)} POP · '
|
||
'${w.weekSfpi == null ? '—' : _signed(w.weekSfpi!)} sFPI',
|
||
),
|
||
),
|
||
row(
|
||
l10n.homeWeeklyMine,
|
||
text(
|
||
'${w.myWeekPop == null ? '—' : formatPop(w.myWeekPop!.round())} POP'
|
||
'${w.myShare == null ? '' : ' · ${(w.myShare! * 100).toStringAsFixed(1)}%'}',
|
||
),
|
||
),
|
||
row(
|
||
l10n.homeWeeklyBalance,
|
||
text(
|
||
'${l10n.popKindGeneral} ${formatPop(w.generalPop)} · '
|
||
'${l10n.popKindContribution} ${formatPop(w.supportPop)}',
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|