feat: adopt material 3 theme and billing adjustments
This commit is contained in:
@@ -4,7 +4,7 @@ import 'package:provider/provider.dart';
|
||||
import '../../models/subscription_model.dart';
|
||||
import '../../services/currency_util.dart';
|
||||
import '../../providers/locale_provider.dart';
|
||||
import '../../theme/app_colors.dart';
|
||||
// import '../../theme/app_colors.dart';
|
||||
|
||||
/// 파이 차트에서 선택된 섹션에 표시되는 배지 위젯
|
||||
class AnalysisBadge extends StatelessWidget {
|
||||
@@ -26,15 +26,15 @@ class AnalysisBadge extends StatelessWidget {
|
||||
width: size,
|
||||
height: size,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.pureWhite,
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: borderColor,
|
||||
width: 2,
|
||||
),
|
||||
boxShadow: const [
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColors.shadowBlack,
|
||||
color: Colors.black.withValues(alpha: 0.08),
|
||||
blurRadius: 10,
|
||||
spreadRadius: 2,
|
||||
),
|
||||
@@ -48,10 +48,10 @@ class AnalysisBadge extends StatelessWidget {
|
||||
subscription.serviceName.length > 5
|
||||
? '${subscription.serviceName.substring(0, 5)}...'
|
||||
: subscription.serviceName,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 8,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.darkNavy,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 0),
|
||||
@@ -82,9 +82,9 @@ class AnalysisBadge extends StatelessWidget {
|
||||
}
|
||||
return Text(
|
||||
displayText,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 7,
|
||||
color: AppColors.navyGray,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../theme/color_scheme_ext.dart';
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'dart:math' as math;
|
||||
import 'package:provider/provider.dart';
|
||||
import '../../services/currency_util.dart';
|
||||
import '../../providers/locale_provider.dart';
|
||||
import '../../theme/app_colors.dart';
|
||||
import '../glassmorphism_card.dart';
|
||||
// Glass 제거: Material 3 Card 사용
|
||||
import '../themed_text.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import '../../utils/reduce_motion.dart';
|
||||
@@ -75,11 +75,13 @@ class MonthlyExpenseChartCard extends StatelessWidget {
|
||||
}
|
||||
|
||||
// 월간 지출 차트 데이터
|
||||
List<BarChartGroupData> _getMonthlyBarGroups(String locale) {
|
||||
List<BarChartGroupData> _getMonthlyBarGroups(
|
||||
BuildContext context, String locale) {
|
||||
final List<BarChartGroupData> barGroups = [];
|
||||
final calculatedMax = monthlyData.fold<double>(
|
||||
0, (max, data) => math.max(max, data['totalExpense'] as double));
|
||||
final maxAmount = _calculateChartMaxY(calculatedMax, locale);
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
|
||||
for (int i = 0; i < monthlyData.length; i++) {
|
||||
final data = monthlyData[i];
|
||||
@@ -89,20 +91,13 @@ class MonthlyExpenseChartCard extends StatelessWidget {
|
||||
barRods: [
|
||||
BarChartRodData(
|
||||
toY: data['totalExpense'],
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
const Color(0xFF3B82F6).withValues(alpha: 0.7),
|
||||
const Color(0xFF60A5FA),
|
||||
],
|
||||
begin: Alignment.bottomCenter,
|
||||
end: Alignment.topCenter,
|
||||
),
|
||||
color: scheme.primary,
|
||||
width: 18,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
backDrawRodData: BackgroundBarChartRodData(
|
||||
show: true,
|
||||
toY: maxAmount,
|
||||
color: AppColors.navyGray.withValues(alpha: 0.1),
|
||||
color: scheme.onSurfaceVariant.withValues(alpha: 0.08),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -132,10 +127,17 @@ class MonthlyExpenseChartCard extends StatelessWidget {
|
||||
parent: animationController,
|
||||
curve: const Interval(0.4, 0.9, 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(
|
||||
@@ -168,7 +170,7 @@ class MonthlyExpenseChartCard extends StatelessWidget {
|
||||
(max, data) => math.max(
|
||||
max, data['totalExpense'] as double)),
|
||||
locale),
|
||||
barGroups: _getMonthlyBarGroups(locale),
|
||||
barGroups: _getMonthlyBarGroups(context, locale),
|
||||
gridData: FlGridData(
|
||||
show: true,
|
||||
drawVerticalLine: false,
|
||||
@@ -182,8 +184,10 @@ class MonthlyExpenseChartCard extends StatelessWidget {
|
||||
CurrencyUtil.getDefaultCurrency(locale)),
|
||||
getDrawingHorizontalLine: (value) {
|
||||
return FlLine(
|
||||
color:
|
||||
AppColors.navyGray.withValues(alpha: 0.1),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurfaceVariant
|
||||
.withValues(alpha: 0.1),
|
||||
strokeWidth: 1,
|
||||
);
|
||||
},
|
||||
@@ -222,14 +226,18 @@ class MonthlyExpenseChartCard extends StatelessWidget {
|
||||
barTouchData: BarTouchData(
|
||||
enabled: true,
|
||||
touchTooltipData: BarTouchTooltipData(
|
||||
tooltipBgColor: AppColors.darkNavy,
|
||||
tooltipBgColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.inverseSurface,
|
||||
tooltipRoundedRadius: 8,
|
||||
getTooltipItem:
|
||||
(group, groupIndex, rod, rodIndex) {
|
||||
return BarTooltipItem(
|
||||
'${monthlyData[group.x]['monthName']}\n',
|
||||
const TextStyle(
|
||||
color: AppColors.pureWhite,
|
||||
TextStyle(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onInverseSurface,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
children: [
|
||||
@@ -239,8 +247,10 @@ class MonthlyExpenseChartCard extends StatelessWidget {
|
||||
monthlyData[group.x]
|
||||
['totalExpense'] as double,
|
||||
locale),
|
||||
style: const TextStyle(
|
||||
color: Color(0xFFFBBF24),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.warning,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
|
||||
@@ -4,8 +4,9 @@ import 'package:provider/provider.dart';
|
||||
import '../../models/subscription_model.dart';
|
||||
import '../../services/currency_util.dart';
|
||||
import '../../services/exchange_rate_service.dart';
|
||||
import '../../theme/app_colors.dart';
|
||||
import '../glassmorphism_card.dart';
|
||||
// import '../../theme/app_colors.dart';
|
||||
import '../../theme/color_scheme_ext.dart';
|
||||
// Glass 제거: Material 3 Card 사용
|
||||
import '../themed_text.dart';
|
||||
import 'analysis_badge.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
@@ -30,18 +31,19 @@ class SubscriptionPieChartCard extends StatefulWidget {
|
||||
|
||||
class _SubscriptionPieChartCardState extends State<SubscriptionPieChartCard> {
|
||||
int _touchedIndex = -1;
|
||||
late Future<List<PieChartSectionData>> _pieSectionsFuture;
|
||||
// kept for compatibility previously; computation now happens per build
|
||||
String? _lastLocale;
|
||||
|
||||
static const _chartColors = [
|
||||
Color(0xFF3B82F6),
|
||||
Color(0xFF10B981),
|
||||
Color(0xFFF59E0B),
|
||||
Color(0xFFEF4444),
|
||||
Color(0xFF8B5CF6),
|
||||
Color(0xFF0EA5E9),
|
||||
Color(0xFFEC4899),
|
||||
];
|
||||
// 차트 팔레트: ColorScheme + 보조 상수(성공/경고/액센트)
|
||||
List<Color> _getChartColors(ColorScheme scheme) => [
|
||||
scheme.primary,
|
||||
scheme.success,
|
||||
scheme.warning,
|
||||
scheme.error,
|
||||
scheme.tertiary,
|
||||
scheme.secondary,
|
||||
const Color(0xFFEC4899), // accent
|
||||
];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -62,7 +64,7 @@ class _SubscriptionPieChartCardState extends State<SubscriptionPieChartCard> {
|
||||
|
||||
void _initializeFuture() {
|
||||
_lastLocale = context.read<LocaleProvider>().locale.languageCode;
|
||||
_pieSectionsFuture = _getPieSections();
|
||||
// no-op: Future computed on demand in build
|
||||
}
|
||||
|
||||
bool _listEquals(List<SubscriptionModel> a, List<SubscriptionModel> b) {
|
||||
@@ -85,6 +87,9 @@ class _SubscriptionPieChartCardState extends State<SubscriptionPieChartCard> {
|
||||
// 현재 locale 가져오기
|
||||
final locale = context.read<LocaleProvider>().locale.languageCode;
|
||||
final defaultCurrency = CurrencyUtil.getDefaultCurrency(locale);
|
||||
// Chart palette (capture scheme before any awaits)
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
final chartColors = _getChartColors(scheme);
|
||||
|
||||
// 개별 구독의 비율 계산을 위한 값들 (기본 통화로 환산)
|
||||
List<double> sectionValues = [];
|
||||
@@ -121,7 +126,7 @@ class _SubscriptionPieChartCardState extends State<SubscriptionPieChartCard> {
|
||||
// 섹션 데이터 생성 (터치 상태 제외)
|
||||
final sections = List.generate(widget.subscriptions.length, (i) {
|
||||
final percentage = (sectionValues[i] / sectionsTotal) * 100;
|
||||
final index = i % _chartColors.length;
|
||||
final index = i % chartColors.length;
|
||||
|
||||
return PieChartSectionData(
|
||||
value: sectionValues[i],
|
||||
@@ -129,12 +134,12 @@ class _SubscriptionPieChartCardState extends State<SubscriptionPieChartCard> {
|
||||
titleStyle: const TextStyle(
|
||||
fontSize: 12.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.pureWhite,
|
||||
color: Colors.white,
|
||||
shadows: [
|
||||
Shadow(color: Colors.black26, blurRadius: 2, offset: Offset(0, 1))
|
||||
],
|
||||
),
|
||||
color: _chartColors[index],
|
||||
color: chartColors[index],
|
||||
radius: 100.0,
|
||||
titlePositionPercentageOffset: 0.6,
|
||||
badgeWidget: null,
|
||||
@@ -150,12 +155,13 @@ class _SubscriptionPieChartCardState extends State<SubscriptionPieChartCard> {
|
||||
if (index >= widget.subscriptions.length) return const SizedBox.shrink();
|
||||
|
||||
final subscription = widget.subscriptions[index];
|
||||
final colorIndex = index % _chartColors.length;
|
||||
final chartColors = _getChartColors(Theme.of(context).colorScheme);
|
||||
final colorIndex = index % chartColors.length;
|
||||
|
||||
return IgnorePointer(
|
||||
child: AnalysisBadge(
|
||||
size: 40,
|
||||
borderColor: _chartColors[colorIndex],
|
||||
borderColor: chartColors[colorIndex],
|
||||
subscription: subscription,
|
||||
),
|
||||
);
|
||||
@@ -177,7 +183,7 @@ class _SubscriptionPieChartCardState extends State<SubscriptionPieChartCard> {
|
||||
TextStyle(
|
||||
fontSize: fontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.pureWhite,
|
||||
color: Colors.white,
|
||||
shadows: const [
|
||||
Shadow(
|
||||
color: Colors.black26, blurRadius: 2, offset: Offset(0, 1))
|
||||
@@ -210,10 +216,17 @@ class _SubscriptionPieChartCardState extends State<SubscriptionPieChartCard> {
|
||||
parent: widget.animationController,
|
||||
curve: const Interval(0.0, 0.7, 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(
|
||||
@@ -243,20 +256,27 @@ class _SubscriptionPieChartCardState extends State<SubscriptionPieChartCard> {
|
||||
vertical: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFE5F2FF),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primary
|
||||
.withValues(alpha: 0.08),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
border: Border.all(
|
||||
color: const Color(0xFFBFDBFE),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primary
|
||||
.withValues(alpha: 0.3),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
AppLocalizations.of(context)
|
||||
.exchangeRateFormat(snapshot.data!),
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF3B82F6),
|
||||
color:
|
||||
Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -291,7 +311,7 @@ class _SubscriptionPieChartCardState extends State<SubscriptionPieChartCard> {
|
||||
: SizedBox(
|
||||
height: 250,
|
||||
child: FutureBuilder<List<PieChartSectionData>>(
|
||||
future: _pieSectionsFuture,
|
||||
future: _getPieSections(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.waiting) {
|
||||
@@ -392,8 +412,10 @@ class _SubscriptionPieChartCardState extends State<SubscriptionPieChartCard> {
|
||||
(index) {
|
||||
final subscription =
|
||||
widget.subscriptions[index];
|
||||
final chartColors = _getChartColors(
|
||||
Theme.of(context).colorScheme);
|
||||
final color =
|
||||
_chartColors[index % _chartColors.length];
|
||||
chartColors[index % chartColors.length];
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 4.0),
|
||||
child: Row(
|
||||
|
||||
@@ -6,8 +6,9 @@ import '../../models/subscription_model.dart';
|
||||
import '../../services/currency_util.dart';
|
||||
import '../../providers/locale_provider.dart';
|
||||
import '../../utils/haptic_feedback_helper.dart';
|
||||
import '../../theme/app_colors.dart';
|
||||
import '../glassmorphism_card.dart';
|
||||
// import '../../theme/app_colors.dart';
|
||||
import '../../theme/color_scheme_ext.dart';
|
||||
// Glass 제거: Material 3 Card 사용
|
||||
import '../themed_text.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
|
||||
@@ -44,10 +45,17 @@ class TotalExpenseSummaryCard extends StatelessWidget {
|
||||
curve: const Interval(0.2, 0.8, curve: Curves.easeOut),
|
||||
)),
|
||||
child: RepaintBoundary(
|
||||
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(
|
||||
@@ -85,8 +93,6 @@ class TotalExpenseSummaryCard extends StatelessWidget {
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
backgroundColor: AppColors.glassBackground
|
||||
.withValues(alpha: 0.3),
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
@@ -142,18 +148,24 @@ class TotalExpenseSummaryCard extends StatelessWidget {
|
||||
Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.glassBackground
|
||||
.withValues(alpha: 0.3),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.surfaceContainerHighest
|
||||
.withValues(alpha: 0.4),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: AppColors.glassBorder
|
||||
.withValues(alpha: 0.2),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.outline
|
||||
.withValues(alpha: 0.3),
|
||||
),
|
||||
),
|
||||
child: const FaIcon(
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.listCheck,
|
||||
size: 16,
|
||||
color: AppColors.primaryColor,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primary,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
@@ -189,18 +201,24 @@ class TotalExpenseSummaryCard extends StatelessWidget {
|
||||
Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.glassBackground
|
||||
.withValues(alpha: 0.3),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.surfaceContainerHighest
|
||||
.withValues(alpha: 0.4),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: AppColors.glassBorder
|
||||
.withValues(alpha: 0.2),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.outline
|
||||
.withValues(alpha: 0.3),
|
||||
),
|
||||
),
|
||||
child: const FaIcon(
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.chartLine,
|
||||
size: 16,
|
||||
color: AppColors.successColor,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.success,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
|
||||
Reference in New Issue
Block a user