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

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:intl/intl.dart';
import '../../models/subscription_model.dart';
import '../../controllers/detail_screen_controller.dart';
@@ -24,10 +25,12 @@ class DetailHeaderSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
final baseColor = controller.getCardColor();
final gradient = controller.getGradient(baseColor);
return Consumer<DetailScreenController>(
builder: (context, controller, child) {
final baseColor = controller.getCardColor();
final gradient = controller.getGradient(baseColor);
return Container(
return Container(
height: 320,
decoration: BoxDecoration(gradient: gradient),
child: Stack(
@@ -118,8 +121,8 @@ class DetailHeaderSection extends StatelessWidget {
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: WebsiteIcon(
url: subscription.websiteUrl,
serviceName: subscription.serviceName,
url: controller.websiteUrlController.text,
serviceName: controller.serviceNameController.text,
size: 48,
),
),
@@ -131,7 +134,7 @@ class DetailHeaderSection extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
subscription.serviceName,
controller.serviceNameController.text,
style: const TextStyle(
fontSize: 28,
fontWeight: FontWeight.w800,
@@ -148,7 +151,7 @@ class DetailHeaderSection extends StatelessWidget {
),
const SizedBox(height: 4),
Text(
'${subscription.billingCycle} 결제',
'${controller.billingCycle} 결제',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
@@ -174,20 +177,22 @@ class DetailHeaderSection extends StatelessWidget {
_InfoColumn(
label: '다음 결제일',
value: DateFormat('yyyy년 MM월 dd일')
.format(subscription.nextBillingDate),
.format(controller.nextBillingDate),
),
_InfoColumn(
label: '월 지출',
value: NumberFormat.currency(
locale: subscription.currency == 'KRW'
locale: controller.currency == 'KRW'
? 'ko_KR'
: 'en_US',
symbol: subscription.currency == 'KRW'
symbol: controller.currency == 'KRW'
? ''
: '\$',
decimalDigits:
subscription.currency == 'KRW' ? 0 : 2,
).format(subscription.monthlyCost),
controller.currency == 'KRW' ? 0 : 2,
).format(double.tryParse(
controller.monthlyCostController.text.replaceAll(',', '')
) ?? 0),
alignment: CrossAxisAlignment.end,
),
],
@@ -204,6 +209,8 @@ class DetailHeaderSection extends StatelessWidget {
],
),
);
},
);
}
}