import 'package:flutter/material.dart'; import 'package:askiineverdie/src/shared/retro_colors.dart'; /// 레트로 RPG 스타일 프로그레스 바 /// 세그먼트 스타일로 8-bit 게임 느낌 재현 class RetroProgressBar extends StatelessWidget { const RetroProgressBar({ super.key, required this.value, this.maxValue = 1.0, this.height = 16, this.segmentCount = 20, this.fillColor = RetroColors.expGreen, this.emptyColor = RetroColors.panelBorderOuter, this.showSegments = true, this.label, this.showPercentage = false, }); /// 현재 값 (0.0 ~ maxValue) final double value; /// 최대 값 final double maxValue; /// 바 높이 final double height; /// 세그먼트 개수 (showSegments가 true일 때) final int segmentCount; /// 채워진 부분 색상 final Color fillColor; /// 빈 부분 색상 final Color emptyColor; /// 세그먼트 표시 여부 final bool showSegments; /// 레이블 (좌측에 표시) final String? label; /// 퍼센트 표시 여부 final bool showPercentage; double get _percentage => maxValue > 0 ? (value / maxValue).clamp(0.0, 1.0) : 0; @override Widget build(BuildContext context) { return Row( children: [ if (label != null) ...[ Text( label!, style: TextStyle( fontFamily: 'PressStart2P', fontSize: height * 0.5, color: RetroColors.textLight, ), ), const SizedBox(width: 8), ], Expanded( child: Container( height: height, decoration: BoxDecoration( color: emptyColor, border: Border.all(color: RetroColors.panelBorderOuter, width: 2), ), child: showSegments ? _buildSegmentedBar() : _buildSolidBar(), ), ), if (showPercentage) ...[ const SizedBox(width: 8), SizedBox( width: 48, child: Text( '${(_percentage * 100).toInt()}%', style: TextStyle( fontFamily: 'PressStart2P', fontSize: height * 0.45, color: RetroColors.textLight, ), textAlign: TextAlign.right, ), ), ], ], ); } Widget _buildSegmentedBar() { final filledSegments = (_percentage * segmentCount).round(); return LayoutBuilder( builder: (context, constraints) { final segmentWidth = constraints.maxWidth / segmentCount; return Row( children: List.generate(segmentCount, (index) { final isFilled = index < filledSegments; return Container( width: segmentWidth, decoration: BoxDecoration( color: isFilled ? fillColor : emptyColor, border: Border( right: index < segmentCount - 1 ? BorderSide( color: RetroColors.panelBorderOuter.withValues(alpha: 0.5), width: 1, ) : BorderSide.none, ), ), ); }), ); }, ); } Widget _buildSolidBar() { return FractionallySizedBox( alignment: Alignment.centerLeft, widthFactor: _percentage, child: Container(color: fillColor), ); } } /// HP 바 (빨간색) class RetroHpBar extends StatelessWidget { const RetroHpBar({ super.key, required this.current, required this.max, this.height = 16, this.showLabel = true, this.showValue = false, }); final int current; final int max; final double height; final bool showLabel; final bool showValue; @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisSize: MainAxisSize.min, children: [ RetroProgressBar( value: current.toDouble(), maxValue: max.toDouble(), height: height, fillColor: RetroColors.hpRed, emptyColor: RetroColors.hpRedDark.withValues(alpha: 0.3), label: showLabel ? 'HP' : null, ), if (showValue) ...[ const SizedBox(height: 2), Text( '$current / $max', style: TextStyle( fontFamily: 'PressStart2P', fontSize: height * 0.4, color: RetroColors.textLight.withValues(alpha: 0.7), ), textAlign: TextAlign.center, ), ], ], ); } } /// MP 바 (파란색) class RetroMpBar extends StatelessWidget { const RetroMpBar({ super.key, required this.current, required this.max, this.height = 16, this.showLabel = true, this.showValue = false, }); final int current; final int max; final double height; final bool showLabel; final bool showValue; @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisSize: MainAxisSize.min, children: [ RetroProgressBar( value: current.toDouble(), maxValue: max.toDouble(), height: height, fillColor: RetroColors.mpBlue, emptyColor: RetroColors.mpBlueDark.withValues(alpha: 0.3), label: showLabel ? 'MP' : null, ), if (showValue) ...[ const SizedBox(height: 2), Text( '$current / $max', style: TextStyle( fontFamily: 'PressStart2P', fontSize: height * 0.4, color: RetroColors.textLight.withValues(alpha: 0.7), ), textAlign: TextAlign.center, ), ], ], ); } } /// EXP 바 (초록색) class RetroExpBar extends StatelessWidget { const RetroExpBar({ super.key, required this.current, required this.max, this.height = 12, this.showLabel = true, this.showPercentage = true, }); final int current; final int max; final double height; final bool showLabel; final bool showPercentage; @override Widget build(BuildContext context) { return RetroProgressBar( value: current.toDouble(), maxValue: max.toDouble(), height: height, fillColor: RetroColors.expGreen, emptyColor: RetroColors.expGreenDark.withValues(alpha: 0.3), label: showLabel ? 'EXP' : null, showPercentage: showPercentage, ); } }