feat: 폼 필드 컴포넌트 분리 및 구독 카드 인터랙션 개선

- billing_cycle_selector, category_selector, currency_selector 컴포넌트 분리
- 구독 카드 클릭 이슈 해결을 위한 리팩토링
- SMS 스캔 화면 UI/UX 개선 및 기능 강화
- 상세 화면 컨트롤러 로직 개선
- 알림 서비스 및 구독 URL 매칭 기능 추가
- CLAUDE.md 프로젝트 가이드라인 대폭 확장
- 전반적인 코드 구조 개선 및 타입 안정성 강화

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
JiWoong Sul
2025-07-14 15:47:46 +09:00
parent 2f60ef585a
commit 111c519883
39 changed files with 2376 additions and 1231 deletions

View File

@@ -4,17 +4,19 @@ import 'package:intl/intl.dart';
/// 카테고리별 구독 그룹의 헤더 위젯
///
/// 카테고리 이름, 구독 개수, 총 비용을 표시합니다.
/// 참고: 여러 통화 단위가된 경우 간단히 원화 표시 형식을 사용합니다.
/// 통화별로 구분하여 표시하며,된 경우 각각 표시합니다.
class CategoryHeaderWidget extends StatelessWidget {
final String categoryName;
final int subscriptionCount;
final double totalCost;
final double totalCostUSD;
final double totalCostKRW;
const CategoryHeaderWidget({
Key? key,
required this.categoryName,
required this.subscriptionCount,
required this.totalCost,
required this.totalCostUSD,
required this.totalCostKRW,
}) : super(key: key);
@override
@@ -36,7 +38,7 @@ class CategoryHeaderWidget extends StatelessWidget {
),
),
Text(
'${subscriptionCount}개 · ${NumberFormat.currency(locale: 'ko_KR', symbol: '', decimalDigits: 0).format(totalCost)}',
_buildCostDisplay(),
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
@@ -55,4 +57,44 @@ class CategoryHeaderWidget extends StatelessWidget {
),
);
}
/// 통화별 합계를 표시하는 문자열을 생성합니다.
String _buildCostDisplay() {
final parts = <String>[];
// 개수는 항상 표시
parts.add('$subscriptionCount개');
// 통화 부분을 별도로 처리
final currencyParts = <String>[];
// 달러가 있는 경우
if (totalCostUSD > 0) {
final formatter = NumberFormat.currency(
locale: 'en_US',
symbol: '\$',
decimalDigits: 2,
);
currencyParts.add(formatter.format(totalCostUSD));
}
// 원화가 있는 경우
if (totalCostKRW > 0) {
final formatter = NumberFormat.currency(
locale: 'ko_KR',
symbol: '',
decimalDigits: 0,
);
currencyParts.add(formatter.format(totalCostKRW));
}
// 통화가 하나 이상 있는 경우
if (currencyParts.isNotEmpty) {
// 통화가 여러 개인 경우 + 로 연결, 하나인 경우 그대로
final currencyDisplay = currencyParts.join(' + ');
parts.add(currencyDisplay);
}
return parts.join(' · ');
}
}