feat: adopt material 3 theme and billing adjustments

This commit is contained in:
JiWoong Sul
2025-09-16 14:30:14 +09:00
parent a01d9092ba
commit 44850a53cc
85 changed files with 2957 additions and 2776 deletions

View File

@@ -3,10 +3,10 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart';
import '../../providers/subscription_provider.dart';
import '../../services/currency_util.dart';
import '../../theme/app_colors.dart';
import '../glassmorphism_card.dart';
// Glass 제거: Material 3 Card 사용
import '../themed_text.dart';
import '../../l10n/app_localizations.dart';
import '../../theme/color_scheme_ext.dart';
/// 이벤트 할인 현황을 보여주는 카드 위젯
class EventAnalysisCard extends StatelessWidget {
@@ -38,10 +38,17 @@ class EventAnalysisCard extends StatelessWidget {
parent: animationController,
curve: const Interval(0.6, 1.0, curve: Curves.easeOut),
)),
child: GlassmorphismCard(
blur: 10,
opacity: 0.1,
borderRadius: 16,
child: Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: BorderSide(
color: Theme.of(context)
.colorScheme
.outline
.withValues(alpha: 0.5),
),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
@@ -64,20 +71,18 @@ class EventAnalysisCard extends StatelessWidget {
vertical: 4,
),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [
Color(0xFFFF6B6B),
Color(0xFFFE7E7E),
],
),
color:
Theme.of(context).colorScheme.error,
borderRadius: BorderRadius.circular(4),
),
child: Row(
children: [
const FaIcon(
FaIcon(
FontAwesomeIcons.fire,
size: 12,
color: AppColors.pureWhite,
color: Theme.of(context)
.colorScheme
.onError,
),
const SizedBox(width: 4),
Text(
@@ -85,10 +90,12 @@ class EventAnalysisCard extends StatelessWidget {
.servicesInProgress(provider
.activeEventSubscriptions
.length),
style: const TextStyle(
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: AppColors.pureWhite,
color: Theme.of(context)
.colorScheme
.onError,
),
),
],
@@ -100,27 +107,24 @@ class EventAnalysisCard extends StatelessWidget {
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
const Color(0xFFFF6B6B)
.withValues(alpha: 0.1),
const Color(0xFFFF8787)
.withValues(alpha: 0.1),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
color: Theme.of(context)
.colorScheme
.error
.withValues(alpha: 0.08),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: const Color(0xFFFF6B6B)
color: Theme.of(context)
.colorScheme
.error
.withValues(alpha: 0.3),
),
),
child: Row(
children: [
const Icon(
Icon(
Icons.savings,
color: Color(0xFFFF6B6B),
color:
Theme.of(context).colorScheme.error,
size: 32,
),
const SizedBox(width: 12),
@@ -142,10 +146,12 @@ class EventAnalysisCard extends StatelessWidget {
CurrencyUtil.formatTotalAmount(
provider.calculateTotalSavings(),
),
style: const TextStyle(
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Color(0xFFFF6B6B),
color: Theme.of(context)
.colorScheme
.error,
),
),
],
@@ -173,12 +179,16 @@ class EventAnalysisCard extends StatelessWidget {
margin: const EdgeInsets.only(bottom: 8),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: AppColors.darkNavy
color: Theme.of(context)
.colorScheme
.onSurface
.withValues(alpha: 0.05),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: AppColors.darkNavy
.withValues(alpha: 0.1),
color: Theme.of(context)
.colorScheme
.onSurfaceVariant
.withValues(alpha: 0.2),
),
),
child: Row(
@@ -207,13 +217,15 @@ class EventAnalysisCard extends StatelessWidget {
if (snapshot.hasData) {
return ThemedText(
snapshot.data!,
style: const TextStyle(
style: TextStyle(
fontSize: 12,
decoration:
TextDecoration
.lineThrough,
color: AppColors
.navyGray,
color: Theme.of(
context)
.colorScheme
.onSurfaceVariant,
),
);
}
@@ -221,10 +233,12 @@ class EventAnalysisCard extends StatelessWidget {
},
),
const SizedBox(width: 8),
const Icon(
Icon(
Icons.arrow_forward,
size: 12,
color: AppColors.navyGray,
color: Theme.of(context)
.colorScheme
.onSurfaceVariant,
),
const SizedBox(width: 8),
FutureBuilder<String>(
@@ -237,12 +251,14 @@ class EventAnalysisCard extends StatelessWidget {
if (snapshot.hasData) {
return ThemedText(
snapshot.data!,
style: const TextStyle(
style: TextStyle(
fontSize: 12,
fontWeight:
FontWeight.bold,
color:
Color(0xFF10B981),
Theme.of(context)
.colorScheme
.success,
),
);
}
@@ -260,17 +276,22 @@ class EventAnalysisCard extends StatelessWidget {
vertical: 4,
),
decoration: BoxDecoration(
color: const Color(0xFFFF6B6B)
color: Theme.of(context)
.colorScheme
.error
.withValues(alpha: 0.2),
borderRadius:
BorderRadius.circular(4),
),
child: Text(
'$discountRate${AppLocalizations.of(context).discountPercent}',
style: const TextStyle(
_formatDiscountPercent(
context, discountRate),
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Color(0xFFFF6B6B),
color: Theme.of(context)
.colorScheme
.error,
),
),
),
@@ -291,3 +312,17 @@ class EventAnalysisCard extends StatelessWidget {
);
}
}
String _formatDiscountPercent(BuildContext context, int percent) {
final raw = AppLocalizations.of(context).discountPercent;
// 우선 @ 플레이스홀더가 있으면 치환
if (raw.contains('@')) {
return raw.replaceAll('@', percent.toString());
}
// % 마커가 있으면 첫 번째 %를 숫자%로 치환
if (raw.contains('%')) {
return raw.replaceFirst('%', '$percent%');
}
// 폴백: "99% text" 형태
return '$percent% $raw';
}