주요 구현 완료 기능: - 구독 관리 (추가/편집/삭제/카테고리 분류) - 이벤트 할인 시스템 (기본값 자동 설정) - SMS 자동 스캔 및 구독 정보 추출 - 알림 시스템 (타임존 처리 안정화) - 환율 변환 지원 (KRW/USD) - 반응형 UI 및 애니메이션 - 다국어 지원 (한국어/영어) 버그 수정: - NotificationService tz.local 초기화 오류 해결 - MainScreenSummaryCard 레이아웃 오버플로우 수정 - 구독 추가 시 LateInitializationError 완전 해결 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
135 lines
3.8 KiB
Dart
135 lines
3.8 KiB
Dart
import 'package:intl/intl.dart';
|
|
import '../models/subscription_model.dart';
|
|
import 'exchange_rate_service.dart';
|
|
|
|
/// 통화 단위 변환 및 포맷팅을 위한 유틸리티 클래스
|
|
class CurrencyUtil {
|
|
static final ExchangeRateService _exchangeRateService = ExchangeRateService();
|
|
|
|
/// 구독 목록의 총 월 비용을 계산 (원화로 환산, 이벤트 가격 반영)
|
|
static Future<double> calculateTotalMonthlyExpense(
|
|
List<SubscriptionModel> subscriptions) async {
|
|
double total = 0.0;
|
|
|
|
for (var subscription in subscriptions) {
|
|
// 이벤트 가격이 있으면 currentPrice 사용
|
|
final price = subscription.currentPrice;
|
|
|
|
if (subscription.currency == 'USD') {
|
|
// USD인 경우 KRW로 변환
|
|
final krwAmount = await _exchangeRateService
|
|
.convertUsdToKrw(price);
|
|
if (krwAmount != null) {
|
|
total += krwAmount;
|
|
}
|
|
} else {
|
|
// KRW인 경우 그대로 합산
|
|
total += price;
|
|
}
|
|
}
|
|
|
|
return total;
|
|
}
|
|
|
|
/// 구독의 월 비용을 표시 형식에 맞게 변환 (원화 변환 포함, 이벤트 가격 반영)
|
|
static Future<String> formatSubscriptionAmount(
|
|
SubscriptionModel subscription) async {
|
|
// 이벤트 가격이 있으면 currentPrice 사용
|
|
final price = subscription.currentPrice;
|
|
|
|
if (subscription.currency == 'USD') {
|
|
// USD 표시 + 원화 환산 금액
|
|
final usdFormatted = NumberFormat.currency(
|
|
locale: 'en_US',
|
|
symbol: '\$',
|
|
decimalDigits: 2,
|
|
).format(price);
|
|
|
|
// 원화 환산 금액
|
|
final krwAmount = await _exchangeRateService
|
|
.getFormattedKrwAmount(price);
|
|
|
|
return '$usdFormatted $krwAmount';
|
|
} else {
|
|
// 원화 표시
|
|
return NumberFormat.currency(
|
|
locale: 'ko_KR',
|
|
symbol: '₩',
|
|
decimalDigits: 0,
|
|
).format(price);
|
|
}
|
|
}
|
|
|
|
/// 총액을 원화로 표시
|
|
static String formatTotalAmount(double amount) {
|
|
return NumberFormat.currency(
|
|
locale: 'ko_KR',
|
|
symbol: '₩',
|
|
decimalDigits: 0,
|
|
).format(amount);
|
|
}
|
|
|
|
/// 환율 정보 텍스트 가져오기
|
|
static Future<String> getExchangeRateInfo() {
|
|
return _exchangeRateService.getFormattedExchangeRateInfo();
|
|
}
|
|
|
|
/// 이벤트로 인한 총 절약액 계산 (원화로 환산)
|
|
static Future<double> calculateTotalEventSavings(
|
|
List<SubscriptionModel> subscriptions) async {
|
|
double total = 0.0;
|
|
|
|
for (var subscription in subscriptions) {
|
|
if (subscription.isCurrentlyInEvent) {
|
|
final savings = subscription.eventSavings;
|
|
|
|
if (subscription.currency == 'USD') {
|
|
// USD인 경우 KRW로 변환
|
|
final krwAmount = await _exchangeRateService
|
|
.convertUsdToKrw(savings);
|
|
if (krwAmount != null) {
|
|
total += krwAmount;
|
|
}
|
|
} else {
|
|
// KRW인 경우 그대로 합산
|
|
total += savings;
|
|
}
|
|
}
|
|
}
|
|
|
|
return total;
|
|
}
|
|
|
|
/// 이벤트 절약액을 표시 형식에 맞게 변환
|
|
static Future<String> formatEventSavings(
|
|
SubscriptionModel subscription) async {
|
|
if (!subscription.isCurrentlyInEvent) {
|
|
return '';
|
|
}
|
|
|
|
final savings = subscription.eventSavings;
|
|
|
|
if (subscription.currency == 'USD') {
|
|
// USD 표시 + 원화 환산 금액
|
|
final usdFormatted = NumberFormat.currency(
|
|
locale: 'en_US',
|
|
symbol: '\$',
|
|
decimalDigits: 2,
|
|
).format(savings);
|
|
|
|
// 원화 환산 금액
|
|
final krwAmount = await _exchangeRateService
|
|
.getFormattedKrwAmount(savings);
|
|
|
|
return '$usdFormatted $krwAmount';
|
|
} else {
|
|
// 원화 표시
|
|
return NumberFormat.currency(
|
|
locale: 'ko_KR',
|
|
symbol: '₩',
|
|
decimalDigits: 0,
|
|
).format(savings);
|
|
}
|
|
}
|
|
}
|