Files
submanager/lib/widgets/sms_scan/subscription_card_widget.dart
2025-09-07 19:33:11 +09:00

319 lines
10 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../models/subscription.dart';
import '../../providers/category_provider.dart';
import '../../providers/locale_provider.dart';
import '../../widgets/themed_text.dart';
import '../../widgets/common/buttons/primary_button.dart';
import '../../widgets/common/buttons/secondary_button.dart';
import '../../widgets/common/form_fields/base_text_field.dart';
import '../../widgets/common/form_fields/category_selector.dart';
import '../../widgets/common/snackbar/app_snackbar.dart';
import '../../widgets/native_ad_widget.dart';
import '../../theme/app_colors.dart';
import '../../services/currency_util.dart';
import '../../utils/sms_scan/date_formatter.dart';
import '../../utils/sms_scan/category_icon_mapper.dart';
import '../../l10n/app_localizations.dart';
class SubscriptionCardWidget extends StatefulWidget {
final Subscription subscription;
final TextEditingController websiteUrlController;
final String? selectedCategoryId;
final Function(String?) onCategoryChanged;
final VoidCallback onAdd;
final VoidCallback onSkip;
const SubscriptionCardWidget({
super.key,
required this.subscription,
required this.websiteUrlController,
this.selectedCategoryId,
required this.onCategoryChanged,
required this.onAdd,
required this.onSkip,
});
@override
State<SubscriptionCardWidget> createState() => _SubscriptionCardWidgetState();
}
class _SubscriptionCardWidgetState extends State<SubscriptionCardWidget> {
@override
void initState() {
super.initState();
// URL 필드 자동 설정
if (widget.websiteUrlController.text.isEmpty &&
widget.subscription.websiteUrl != null) {
widget.websiteUrlController.text = widget.subscription.websiteUrl!;
}
}
void _handleCardTap() {
// 구독 카드 클릭 시 처리
AppSnackBar.showInfo(
context: context,
message: AppLocalizations.of(context).featureComingSoon,
icon: Icons.info_outline,
);
}
@override
Widget build(BuildContext context) {
final categoryProvider = Provider.of<CategoryProvider>(context);
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// 광고 위젯 추가
const NativeAdWidget(key: ValueKey('sms_scan_result_ad')),
const SizedBox(height: 16),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// 구독 정보 카드
ClipRRect(
borderRadius: BorderRadius.circular(16.0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: AppColors.glassCard,
borderRadius: BorderRadius.circular(16.0),
border: Border.all(
color: AppColors.glassBorder,
width: 1,
),
boxShadow: const [
BoxShadow(
color: AppColors.shadowBlack,
blurRadius: 20,
spreadRadius: -5,
offset: Offset(0, 10),
),
],
),
child: Column(
children: [
// 클릭 가능한 정보 영역
Material(
color: Colors.transparent,
child: InkWell(
onTap: _handleCardTap,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16.0),
topRight: Radius.circular(16.0),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: _buildInfoSection(categoryProvider),
),
),
),
// 구분선
Container(
height: 1,
color: AppColors.navyGray.withValues(alpha: 0.1),
),
// 클릭 불가능한 액션 영역
Padding(
padding: const EdgeInsets.all(16.0),
child: _buildActionSection(categoryProvider),
),
],
),
),
),
],
),
),
],
);
}
// 정보 섹션 (클릭 가능)
Widget _buildInfoSection(CategoryProvider categoryProvider) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ThemedText(
AppLocalizations.of(context).foundSubscription,
fontSize: 18,
fontWeight: FontWeight.bold,
forceDark: true,
),
const SizedBox(height: 24),
// 서비스명
ThemedText(
AppLocalizations.of(context).serviceName,
fontWeight: FontWeight.w500,
opacity: 0.7,
forceDark: true,
),
const SizedBox(height: 4),
ThemedText(
widget.subscription.serviceName,
fontSize: 22,
fontWeight: FontWeight.bold,
forceDark: true,
),
const SizedBox(height: 16),
// 금액 및 결제 주기
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ThemedText(
AppLocalizations.of(context).monthlyCost,
fontWeight: FontWeight.w500,
opacity: 0.7,
forceDark: true,
),
const SizedBox(height: 4),
// 언어별 통화 표시
FutureBuilder<String>(
future: CurrencyUtil.formatAmountWithLocale(
widget.subscription.monthlyCost,
widget.subscription.currency,
context.read<LocaleProvider>().locale.languageCode,
),
builder: (context, snapshot) {
return ThemedText(
snapshot.data ?? '-',
fontSize: 18,
fontWeight: FontWeight.bold,
forceDark: true,
);
},
),
],
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ThemedText(
AppLocalizations.of(context).billingCycle,
fontWeight: FontWeight.w500,
opacity: 0.7,
forceDark: true,
),
const SizedBox(height: 4),
ThemedText(
widget.subscription.billingCycle,
fontSize: 16,
fontWeight: FontWeight.w500,
forceDark: true,
),
],
),
),
],
),
const SizedBox(height: 16),
// 다음 결제일
ThemedText(
AppLocalizations.of(context).nextBillingDateLabel,
fontWeight: FontWeight.w500,
opacity: 0.7,
forceDark: true,
),
const SizedBox(height: 4),
ThemedText(
SmsDateFormatter.getNextBillingText(
context,
widget.subscription.nextBillingDate,
widget.subscription.billingCycle,
),
fontSize: 16,
fontWeight: FontWeight.w500,
forceDark: true,
),
],
);
}
// 액션 섹션 (클릭 불가능)
Widget _buildActionSection(CategoryProvider categoryProvider) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 카테고리 선택
ThemedText(
AppLocalizations.of(context).category,
fontWeight: FontWeight.w500,
opacity: 0.7,
forceDark: true,
),
const SizedBox(height: 8),
CategorySelector(
categories: categoryProvider.categories,
selectedCategoryId:
widget.selectedCategoryId ?? widget.subscription.category,
onChanged: widget.onCategoryChanged,
baseColor: _getCategoryColor(categoryProvider),
isGlassmorphism: true,
),
const SizedBox(height: 24),
// 웹사이트 URL 입력 필드
BaseTextField(
controller: widget.websiteUrlController,
label: AppLocalizations.of(context).websiteUrlAuto,
hintText: AppLocalizations.of(context).websiteUrlHint,
prefixIcon: const Icon(
Icons.language,
color: AppColors.navyGray,
),
style: const TextStyle(
color: AppColors.darkNavy,
),
fillColor: AppColors.pureWhite.withValues(alpha: 0.8),
),
const SizedBox(height: 32),
// 작업 버튼
Row(
children: [
Expanded(
child: SecondaryButton(
text: AppLocalizations.of(context).skip,
onPressed: widget.onSkip,
height: 48,
),
),
const SizedBox(width: 16),
Expanded(
child: PrimaryButton(
text: AppLocalizations.of(context).add,
onPressed: widget.onAdd,
height: 48,
),
),
],
),
],
);
}
Color? _getCategoryColor(CategoryProvider categoryProvider) {
final categoryId =
widget.selectedCategoryId ?? widget.subscription.category;
if (categoryId == null) return null;
final category = categoryProvider.getCategoryById(categoryId);
if (category == null) return null;
return CategoryIconMapper.getCategoryColor(category);
}
}