feat: 다국어 지원 및 다중 통화 환율 변환 기능 확대

- ExchangeRateService에 JPY, CNY 환율 지원 추가
- 구독 서비스별 다국어 표시 이름 지원
- 분석 화면 차트 및 UI/UX 개선
- 설정 화면 전면 리팩토링
- SMS 스캔 기능 사용성 개선
- 전체 앱 다국어 번역 확대

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
JiWoong Sul
2025-07-16 17:34:32 +09:00
parent 4d1c0f5dab
commit 0f0b02bf08
55 changed files with 4100 additions and 1197 deletions

View File

@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import '../../../theme/app_colors.dart';
/// 통화 선택 위젯
/// KRW(원화) USD(달러) 중 선택할 수 있습니다.
/// KRW(원화), USD(달러), JPY(엔화), CNY(위안화) 중 선택할 수 있습니다.
class CurrencySelector extends StatelessWidget {
final String currency;
final ValueChanged<String> onChanged;
@@ -17,22 +17,48 @@ class CurrencySelector extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Row(
return Column(
children: [
_CurrencyOption(
label: '',
value: 'KRW',
isSelected: currency == 'KRW',
onTap: () => onChanged('KRW'),
isGlassmorphism: isGlassmorphism,
Row(
children: [
_CurrencyOption(
label: '',
value: 'KRW',
isSelected: currency == 'KRW',
onTap: () => onChanged('KRW'),
isGlassmorphism: isGlassmorphism,
),
const SizedBox(width: 8),
_CurrencyOption(
label: '\$',
value: 'USD',
isSelected: currency == 'USD',
onTap: () => onChanged('USD'),
isGlassmorphism: isGlassmorphism,
),
],
),
const SizedBox(width: 8),
_CurrencyOption(
label: '\$',
value: 'USD',
isSelected: currency == 'USD',
onTap: () => onChanged('USD'),
isGlassmorphism: isGlassmorphism,
const SizedBox(height: 8),
Row(
children: [
_CurrencyOption(
label: '¥',
value: 'JPY',
subtitle: 'JPY',
isSelected: currency == 'JPY',
onTap: () => onChanged('JPY'),
isGlassmorphism: isGlassmorphism,
),
const SizedBox(width: 8),
_CurrencyOption(
label: '¥',
value: 'CNY',
subtitle: 'CNY',
isSelected: currency == 'CNY',
onTap: () => onChanged('CNY'),
isGlassmorphism: isGlassmorphism,
),
],
),
],
);
@@ -43,6 +69,7 @@ class CurrencySelector extends StatelessWidget {
class _CurrencyOption extends StatelessWidget {
final String label;
final String value;
final String? subtitle;
final bool isSelected;
final VoidCallback onTap;
final bool isGlassmorphism;
@@ -50,6 +77,7 @@ class _CurrencyOption extends StatelessWidget {
const _CurrencyOption({
required this.label,
required this.value,
this.subtitle,
required this.isSelected,
required this.onTap,
required this.isGlassmorphism,
@@ -71,13 +99,29 @@ class _CurrencyOption extends StatelessWidget {
border: _getBorder(),
),
child: Center(
child: Text(
label,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: _getTextColor(),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
label,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: _getTextColor(),
),
),
if (subtitle != null) ...[
const SizedBox(height: 2),
Text(
subtitle!,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w500,
color: _getTextColor().withValues(alpha: 0.8),
),
),
],
],
),
),
),