feat: SMS 스캔 화면 리팩토링 및 MVC 패턴 적용

- SMS 스캔 화면을 컨트롤러/서비스/위젯으로 분리
- 코드 가독성 및 유지보수성 향상
- 새로운 다국어 지원 키 추가
- Git 커밋 가이드라인 문서화
This commit is contained in:
JiWoong Sul
2025-07-17 16:59:19 +09:00
parent 91bc91383b
commit 186d1bbf66
20 changed files with 1794 additions and 1408 deletions

View File

@@ -0,0 +1,53 @@
import 'package:flutter/material.dart';
import '../../models/category_model.dart';
class CategoryIconMapper {
// 카테고리 아이콘 반환
static IconData getCategoryIcon(CategoryModel category) {
switch (category.name) {
case 'music':
return Icons.music_note_rounded;
case 'ottVideo':
return Icons.movie_filter_rounded;
case 'storageCloud':
return Icons.cloud_outlined;
case 'telecomInternetTv':
return Icons.wifi_rounded;
case 'lifestyle':
return Icons.home_outlined;
case 'shoppingEcommerce':
return Icons.shopping_cart_outlined;
case 'programming':
return Icons.code_rounded;
case 'collaborationOffice':
return Icons.business_center_outlined;
case 'aiService':
return Icons.smart_toy_outlined;
case 'other':
default:
return Icons.category_outlined;
}
}
// 카테고리별 배경색 반환
static Color getCategoryColor(CategoryModel category) {
final colorString = category.color;
try {
return Color(int.parse(colorString.replaceFirst('#', '0xFF')));
} catch (e) {
// 파싱 실패 시 기본 색상 반환
return const Color(0xFF6B7280); // 기본 회색
}
}
// 카테고리별 아이콘 크기 반환
static double getCategoryIconSize(CategoryModel category) {
switch (category.name) {
case 'music':
case 'ottVideo':
return 18.0;
default:
return 16.0;
}
}
}

View File

@@ -0,0 +1,165 @@
import 'package:flutter/material.dart';
import '../../l10n/app_localizations.dart';
class SmsDateFormatter {
// 날짜 상태 텍스트 가져오기
static String getNextBillingText(
BuildContext context,
DateTime date,
String billingCycle,
) {
final now = DateTime.now();
if (date.isBefore(now)) {
return _getPastDateText(context, date, billingCycle, now);
} else {
return _getFutureDateText(context, date, now);
}
}
// 과거 날짜 처리
static String _getPastDateText(
BuildContext context,
DateTime date,
String billingCycle,
DateTime now,
) {
// 주기에 따라 다음 결제일 예측
DateTime? predictedDate = _predictNextBillingDate(date, billingCycle, now);
if (predictedDate != null) {
final daysUntil = predictedDate.difference(now).inDays;
return AppLocalizations.of(context).nextBillingDateEstimated(
AppLocalizations.of(context).formatDate(predictedDate),
daysUntil,
);
}
return '다음 결제일 확인 필요 (과거 날짜)';
}
// 미래 날짜 처리
static String _getFutureDateText(
BuildContext context,
DateTime date,
DateTime now,
) {
final daysUntil = date.difference(now).inDays;
return AppLocalizations.of(context).nextBillingDateInfo(
AppLocalizations.of(context).formatDate(date),
daysUntil,
);
}
// 다음 결제일 예측
static DateTime? _predictNextBillingDate(
DateTime lastDate,
String billingCycle,
DateTime now,
) {
switch (billingCycle) {
case '월간':
return _getNextMonthlyDate(lastDate, now);
case '연간':
return _getNextYearlyDate(lastDate, now);
case '주간':
return _getNextWeeklyDate(lastDate, now);
case '일간':
return _getNextDailyDate(lastDate, now);
case '분기별':
return _getNextQuarterlyDate(lastDate, now);
case '반기별':
return _getNextSemiAnnuallyDate(lastDate, now);
default:
return null;
}
}
// 다음 월간 결제일 계산
static DateTime _getNextMonthlyDate(DateTime lastDate, DateTime now) {
int day = lastDate.day;
// 현재 월의 마지막 날을 초과하는 경우 조정
final lastDay = DateTime(now.year, now.month + 1, 0).day;
if (day > lastDay) {
day = lastDay;
}
DateTime adjusted = DateTime(now.year, now.month, day);
if (adjusted.isBefore(now)) {
// 다음 달의 마지막 날을 초과하는 경우 조정
final nextMonthLastDay = DateTime(now.year, now.month + 2, 0).day;
if (day > nextMonthLastDay) {
day = nextMonthLastDay;
}
adjusted = DateTime(now.year, now.month + 1, day);
}
return adjusted;
}
// 다음 연간 결제일 계산
static DateTime _getNextYearlyDate(DateTime lastDate, DateTime now) {
int day = lastDate.day;
// 해당 월의 마지막 날을 초과하는 경우 조정
final lastDay = DateTime(now.year, lastDate.month + 1, 0).day;
if (day > lastDay) {
day = lastDay;
}
DateTime adjusted = DateTime(now.year, lastDate.month, day);
if (adjusted.isBefore(now)) {
// 다음 해 해당 월의 마지막 날을 초과하는 경우 조정
final nextYearLastDay = DateTime(now.year + 1, lastDate.month + 1, 0).day;
if (day > nextYearLastDay) {
day = nextYearLastDay;
}
adjusted = DateTime(now.year + 1, lastDate.month, day);
}
return adjusted;
}
// 다음 주간 결제일 계산
static DateTime _getNextWeeklyDate(DateTime lastDate, DateTime now) {
DateTime next = lastDate;
while (next.isBefore(now)) {
next = next.add(const Duration(days: 7));
}
return next;
}
// 다음 일간 결제일 계산
static DateTime _getNextDailyDate(DateTime lastDate, DateTime now) {
return now.add(const Duration(days: 1));
}
// 다음 분기별 결제일 계산
static DateTime _getNextQuarterlyDate(DateTime lastDate, DateTime now) {
DateTime next = lastDate;
while (next.isBefore(now)) {
next = DateTime(next.year, next.month + 3, next.day);
}
return next;
}
// 다음 반기별 결제일 계산
static DateTime _getNextSemiAnnuallyDate(DateTime lastDate, DateTime now) {
DateTime next = lastDate;
while (next.isBefore(now)) {
next = DateTime(next.year, next.month + 6, next.day);
}
return next;
}
// 날짜 포맷 함수
static String formatDate(DateTime date) {
return '${date.year}${date.month}${date.day}';
}
// 결제 반복 횟수 텍스트
static String getRepeatCountText(BuildContext context, int count) {
return AppLocalizations.of(context).repeatCountDetected(count);
}
}