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:
@@ -1,6 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../models/subscription_model.dart';
|
||||
import '../providers/category_provider.dart';
|
||||
import 'website_icon.dart';
|
||||
import 'app_navigator.dart';
|
||||
import '../theme/app_colors.dart';
|
||||
@@ -8,10 +10,12 @@ import 'glassmorphism_card.dart';
|
||||
|
||||
class SubscriptionCard extends StatefulWidget {
|
||||
final SubscriptionModel subscription;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
const SubscriptionCard({
|
||||
super.key,
|
||||
required this.subscription,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -190,6 +194,34 @@ class _SubscriptionCardState extends State<SubscriptionCard>
|
||||
return false;
|
||||
}
|
||||
|
||||
// 카테고리별 그라데이션 색상 생성
|
||||
List<Color> _getCategoryGradientColors(BuildContext context) {
|
||||
try {
|
||||
if (widget.subscription.categoryId == null) {
|
||||
return AppColors.blueGradient;
|
||||
}
|
||||
|
||||
final categoryProvider = context.watch<CategoryProvider>();
|
||||
final category = categoryProvider.getCategoryById(widget.subscription.categoryId!);
|
||||
|
||||
if (category == null) {
|
||||
return AppColors.blueGradient;
|
||||
}
|
||||
|
||||
final categoryColor = Color(
|
||||
int.parse(category.color.replaceAll('#', '0xFF'))
|
||||
);
|
||||
|
||||
return [
|
||||
categoryColor,
|
||||
categoryColor.withValues(alpha: 0.8),
|
||||
];
|
||||
} catch (e) {
|
||||
// 색상 파싱 실패 시 기본 파란색 그라데이션 반환
|
||||
return AppColors.blueGradient;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -200,53 +232,39 @@ class _SubscriptionCardState extends State<SubscriptionCard>
|
||||
child: MouseRegion(
|
||||
onEnter: (_) => _onHover(true),
|
||||
onExit: (_) => _onHover(false),
|
||||
child: AnimatedBuilder(
|
||||
animation: _hoverController,
|
||||
builder: (context, child) {
|
||||
final scale = 1.0 + (0.02 * _hoverController.value);
|
||||
child: AnimatedGlassmorphismCard(
|
||||
padding: EdgeInsets.zero,
|
||||
borderRadius: 16,
|
||||
blur: _isHovering ? 15 : 10,
|
||||
width: double.infinity, // 전체 너비를 차지하도록 설정
|
||||
onTap: widget.onTap ?? () async {
|
||||
await AppNavigator.toDetail(context, widget.subscription);
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
// 그라데이션 상단 바 효과
|
||||
AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: widget.subscription.isCurrentlyInEvent
|
||||
? [
|
||||
const Color(0xFFFF6B6B),
|
||||
const Color(0xFFFF8787),
|
||||
]
|
||||
: isNearBilling
|
||||
? AppColors.amberGradient
|
||||
: _getCategoryGradientColors(context),
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
return Transform.scale(
|
||||
scale: scale,
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
await AppNavigator.toDetail(context, widget.subscription);
|
||||
},
|
||||
splashColor: AppColors.primaryColor.withValues(alpha: 0.1),
|
||||
highlightColor: AppColors.primaryColor.withValues(alpha: 0.05),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: AnimatedGlassmorphismCard(
|
||||
onTap: () {}, // onTap은 이미 InkWell에서 처리됨
|
||||
padding: EdgeInsets.zero,
|
||||
borderRadius: 16,
|
||||
blur: _isHovering ? 15 : 10,
|
||||
width: double.infinity, // 전체 너비를 차지하도록 설정
|
||||
child: Column(
|
||||
children: [
|
||||
// 그라데이션 상단 바 효과
|
||||
AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: widget.subscription.isCurrentlyInEvent
|
||||
? [
|
||||
const Color(0xFFFF6B6B),
|
||||
const Color(0xFFFF8787),
|
||||
]
|
||||
: isNearBilling
|
||||
? AppColors.amberGradient
|
||||
: AppColors.blueGradient,
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 서비스 아이콘
|
||||
@@ -304,7 +322,7 @@ class _SubscriptionCardState extends State<SubscriptionCard>
|
||||
borderRadius:
|
||||
BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(
|
||||
child: const Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
@@ -526,15 +544,10 @@ class _SubscriptionCardState extends State<SubscriptionCard>
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user