feat: adopt material 3 theme and billing adjustments
This commit is contained in:
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
|
||||
@@ -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: [
|
||||
// 배경 패턴
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user