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

@@ -1,7 +1,8 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../controllers/detail_screen_controller.dart';
import '../../theme/app_colors.dart';
import '../../theme/color_scheme_ext.dart';
// import '../../theme/app_colors.dart';
import '../common/form_fields/currency_input_field.dart';
import '../common/form_fields/date_picker_field.dart';
import '../../l10n/app_localizations.dart';
@@ -38,19 +39,15 @@ class DetailEventSection extends StatelessWidget {
)),
child: Container(
decoration: BoxDecoration(
color: AppColors.glassCard,
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: AppColors.glassBorder.withValues(alpha: 0.1),
color: Theme.of(context)
.colorScheme
.outline
.withValues(alpha: 0.3),
width: 1,
),
boxShadow: const [
BoxShadow(
color: AppColors.shadowBlack,
blurRadius: 10,
offset: Offset(0, 4),
),
],
),
child: Padding(
padding: const EdgeInsets.all(24),
@@ -78,10 +75,10 @@ class DetailEventSection extends StatelessWidget {
const SizedBox(width: 12),
Text(
AppLocalizations.of(context).eventPrice,
style: const TextStyle(
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
color: AppColors.darkNavy,
color: Theme.of(context).colorScheme.onSurface,
),
),
],
@@ -98,7 +95,8 @@ class DetailEventSection extends StatelessWidget {
controller.eventPriceController.clear();
}
},
activeColor: baseColor,
activeThumbColor: baseColor,
activeTrackColor: baseColor.withValues(alpha: 0.5),
),
],
),
@@ -109,27 +107,34 @@ class DetailEventSection extends StatelessWidget {
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: AppColors.infoColor.withValues(alpha: 0.08),
color: Theme.of(context)
.colorScheme
.tertiary
.withValues(alpha: 0.08),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: AppColors.infoColor.withValues(alpha: 0.3),
color: Theme.of(context)
.colorScheme
.tertiary
.withValues(alpha: 0.3),
width: 1,
),
),
child: Row(
children: [
const Icon(
Icon(
Icons.info_outline_rounded,
color: AppColors.infoColor,
color: Theme.of(context).colorScheme.tertiary,
size: 20,
),
const SizedBox(width: 8),
Expanded(
child: Text(
AppLocalizations.of(context).eventPriceHint,
style: const TextStyle(
style: TextStyle(
fontSize: 14,
color: AppColors.darkNavy,
color:
Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w500,
),
),
@@ -228,7 +233,7 @@ class _DiscountBadge extends StatelessWidget {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.green.withValues(alpha: 0.1),
color: Theme.of(context).colorScheme.success.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12),
),
child: Row(
@@ -236,15 +241,15 @@ class _DiscountBadge extends StatelessWidget {
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.green,
color: Theme.of(context).colorScheme.success,
borderRadius: BorderRadius.circular(8),
),
child: Text(
AppLocalizations.of(context)
.discountPercent
.replaceAll('@', discountPercentage.toString()),
style: const TextStyle(
color: Colors.white,
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimary,
fontSize: 12,
fontWeight: FontWeight.w600,
),
@@ -253,8 +258,8 @@ class _DiscountBadge extends StatelessWidget {
const SizedBox(width: 12),
Text(
_getLocalizedDiscountAmount(context, currency, discountAmount),
style: const TextStyle(
color: Color(0xFF15803D),
style: TextStyle(
color: Theme.of(context).colorScheme.success,
fontSize: 14,
fontWeight: FontWeight.w500,
),

View File

@@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../controllers/detail_screen_controller.dart';
import '../../providers/category_provider.dart';
import '../../theme/app_colors.dart';
import '../common/form_fields/base_text_field.dart';
import '../common/form_fields/currency_input_field.dart';
import '../common/form_fields/date_picker_field.dart';
import '../common/form_fields/currency_selector.dart';
// import '../common/form_fields/currency_selector.dart';
import '../common/form_fields/currency_dropdown_field.dart';
import '../common/form_fields/billing_cycle_selector.dart';
import '../common/form_fields/category_selector.dart';
import '../../l10n/app_localizations.dart';
@@ -43,19 +43,15 @@ class DetailFormSection extends StatelessWidget {
)),
child: Container(
decoration: BoxDecoration(
color: AppColors.glassCard,
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: AppColors.glassBorder.withValues(alpha: 0.1),
color: Theme.of(context)
.colorScheme
.outline
.withValues(alpha: 0.3),
width: 1,
),
boxShadow: const [
BoxShadow(
color: AppColors.shadowBlack,
blurRadius: 10,
offset: Offset(0, 4),
),
],
),
child: Padding(
padding: const EdgeInsets.all(24),
@@ -100,28 +96,18 @@ class DetailFormSection extends StatelessWidget {
children: [
Text(
AppLocalizations.of(context).currency,
style: const TextStyle(
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.darkNavy,
color:
Theme.of(context).colorScheme.onSurface,
),
),
const SizedBox(height: 8),
CurrencySelector(
CurrencyDropdownField(
currency: controller.currency,
isGlassmorphism: true,
onChanged: (value) {
controller.currency = value;
// 통화 변경시 금액 포맷 업데이트
if (value == 'KRW') {
final amount = double.tryParse(controller
.monthlyCostController.text
.replaceAll(',', ''));
if (amount != null) {
controller.monthlyCostController.text =
amount.toInt().toString();
}
}
},
),
],
@@ -137,17 +123,16 @@ class DetailFormSection extends StatelessWidget {
children: [
Text(
AppLocalizations.of(context).billingCycle,
style: const TextStyle(
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.darkNavy,
color: Theme.of(context).colorScheme.onSurface,
),
),
const SizedBox(height: 8),
BillingCycleSelector(
billingCycle: controller.billingCycle,
baseColor: baseColor,
isGlassmorphism: true,
onChanged: (value) {
controller.billingCycle = value;
},
@@ -163,7 +148,9 @@ class DetailFormSection extends StatelessWidget {
controller.nextBillingDate = date;
},
label: AppLocalizations.of(context).nextBillingDate,
firstDate: DateTime.now(),
// 과거 결제일을 가진 항목도 수정 가능하도록 범위 완화
firstDate: DateTime.now()
.subtract(const Duration(days: 365 * 10)),
lastDate:
DateTime.now().add(const Duration(days: 365 * 2)),
primaryColor: baseColor,
@@ -178,10 +165,10 @@ class DetailFormSection extends StatelessWidget {
children: [
Text(
AppLocalizations.of(context).category,
style: const TextStyle(
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.darkNavy,
color: Theme.of(context).colorScheme.onSurface,
),
),
const SizedBox(height: 8),
@@ -189,7 +176,6 @@ class DetailFormSection extends StatelessWidget {
categories: categoryProvider.categories,
selectedCategoryId: controller.selectedCategoryId,
baseColor: baseColor,
isGlassmorphism: true,
onChanged: (categoryId) {
controller.selectedCategoryId = categoryId;
},

View File

@@ -30,11 +30,10 @@ class DetailHeaderSection extends StatelessWidget {
return Consumer<DetailScreenController>(
builder: (context, controller, child) {
final baseColor = controller.getCardColor();
final gradient = controller.getGradient(baseColor);
return Container(
height: 320,
decoration: BoxDecoration(gradient: gradient),
decoration: BoxDecoration(color: baseColor),
child: Stack(
children: [
// 배경 패턴

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import '../../controllers/detail_screen_controller.dart';
import '../../theme/app_colors.dart';
import '../../theme/color_scheme_ext.dart';
import '../common/form_fields/base_text_field.dart';
import '../common/buttons/secondary_button.dart';
import '../../l10n/app_localizations.dart';
@@ -35,19 +35,13 @@ class DetailUrlSection extends StatelessWidget {
)),
child: Container(
decoration: BoxDecoration(
color: AppColors.glassCard,
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: AppColors.glassBorder.withValues(alpha: 0.1),
color:
Theme.of(context).colorScheme.outline.withValues(alpha: 0.3),
width: 1,
),
boxShadow: const [
BoxShadow(
color: AppColors.shadowBlack,
blurRadius: 10,
offset: Offset(0, 4),
),
],
),
child: Padding(
padding: const EdgeInsets.all(24),
@@ -72,10 +66,10 @@ class DetailUrlSection extends StatelessWidget {
const SizedBox(width: 12),
Text(
AppLocalizations.of(context).websiteInfo,
style: const TextStyle(
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
color: AppColors.darkNavy,
color: Theme.of(context).colorScheme.onSurface,
),
),
],
@@ -89,9 +83,9 @@ class DetailUrlSection extends StatelessWidget {
label: AppLocalizations.of(context).websiteUrl,
hintText: AppLocalizations.of(context).urlExample,
keyboardType: TextInputType.url,
prefixIcon: const Icon(
prefixIcon: Icon(
Icons.link_rounded,
color: AppColors.navyGray,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
@@ -102,10 +96,16 @@ class DetailUrlSection extends StatelessWidget {
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColors.warningColor.withValues(alpha: 0.08),
color: Theme.of(context)
.colorScheme
.warning
.withValues(alpha: 0.08),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: AppColors.warningColor.withValues(alpha: 0.4),
color: Theme.of(context)
.colorScheme
.warning
.withValues(alpha: 0.4),
width: 1,
),
),
@@ -114,18 +114,18 @@ class DetailUrlSection extends StatelessWidget {
children: [
Row(
children: [
const Icon(
Icon(
Icons.info_outline_rounded,
color: AppColors.warningColor,
color: Theme.of(context).colorScheme.warning,
size: 20,
),
const SizedBox(width: 8),
Text(
AppLocalizations.of(context).cancelGuide,
style: const TextStyle(
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.darkNavy,
color: Theme.of(context).colorScheme.onSurface,
),
),
],
@@ -133,9 +133,9 @@ class DetailUrlSection extends StatelessWidget {
const SizedBox(height: 8),
Text(
AppLocalizations.of(context).cancelServiceGuide,
style: const TextStyle(
style: TextStyle(
fontSize: 14,
color: AppColors.darkNavy,
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w500,
height: 1.5,
),
@@ -145,7 +145,7 @@ class DetailUrlSection extends StatelessWidget {
text: AppLocalizations.of(context).goToCancelPage,
icon: Icons.open_in_new_rounded,
onPressed: controller.openCancellationPage,
color: AppColors.warningColor,
color: Theme.of(context).colorScheme.warning,
),
],
),
@@ -158,27 +158,33 @@ class DetailUrlSection extends StatelessWidget {
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: AppColors.infoColor.withValues(alpha: 0.08),
color: Theme.of(context)
.colorScheme
.info
.withValues(alpha: 0.08),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: AppColors.infoColor.withValues(alpha: 0.3),
color: Theme.of(context)
.colorScheme
.info
.withValues(alpha: 0.3),
width: 1,
),
),
child: Row(
children: [
const Icon(
Icon(
Icons.auto_fix_high_rounded,
color: AppColors.infoColor,
color: Theme.of(context).colorScheme.info,
size: 20,
),
const SizedBox(width: 8),
Expanded(
child: Text(
AppLocalizations.of(context).urlAutoMatchInfo,
style: const TextStyle(
style: TextStyle(
fontSize: 14,
color: AppColors.darkNavy,
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w500,
),
),