feat: 폼 필드 컴포넌트 분리 및 구독 카드 인터랙션 개선
- billing_cycle_selector, category_selector, currency_selector 컴포넌트 분리 - 구독 카드 클릭 이슈 해결을 위한 리팩토링 - SMS 스캔 화면 UI/UX 개선 및 기능 강화 - 상세 화면 컨트롤러 로직 개선 - 알림 서비스 및 구독 URL 매칭 기능 추가 - CLAUDE.md 프로젝트 가이드라인 대폭 확장 - 전반적인 코드 구조 개선 및 타입 안정성 강화 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -103,7 +103,7 @@ class BaseTextField extends StatelessWidget {
|
||||
prefixText: prefixText,
|
||||
suffixIcon: suffixIcon,
|
||||
filled: true,
|
||||
fillColor: fillColor ?? AppColors.glassBackground,
|
||||
fillColor: fillColor ?? AppColors.surfaceColorAlt,
|
||||
contentPadding: contentPadding ?? const EdgeInsets.all(16),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
@@ -119,8 +119,8 @@ class BaseTextField extends StatelessWidget {
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
borderSide: BorderSide(
|
||||
color: AppColors.textSecondary,
|
||||
width: 1,
|
||||
color: AppColors.borderColor.withValues(alpha: 0.7),
|
||||
width: 1.5,
|
||||
),
|
||||
),
|
||||
disabledBorder: OutlineInputBorder(
|
||||
|
||||
101
lib/widgets/common/form_fields/billing_cycle_selector.dart
Normal file
101
lib/widgets/common/form_fields/billing_cycle_selector.dart
Normal file
@@ -0,0 +1,101 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../theme/app_colors.dart';
|
||||
|
||||
/// 결제 주기 선택 위젯
|
||||
/// 월간, 분기별, 반기별, 연간 중 선택할 수 있습니다.
|
||||
class BillingCycleSelector extends StatelessWidget {
|
||||
final String billingCycle;
|
||||
final ValueChanged<String> onChanged;
|
||||
final Color? baseColor;
|
||||
final List<Color>? gradientColors;
|
||||
final bool isGlassmorphism;
|
||||
|
||||
const BillingCycleSelector({
|
||||
super.key,
|
||||
required this.billingCycle,
|
||||
required this.onChanged,
|
||||
this.baseColor,
|
||||
this.gradientColors,
|
||||
this.isGlassmorphism = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// 상세 화면에서는 '매월', 추가 화면에서는 '월간'으로 표시
|
||||
final cycles = isGlassmorphism
|
||||
? ['매월', '분기별', '반기별', '매년']
|
||||
: ['월간', '분기별', '반기별', '연간'];
|
||||
|
||||
return SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: cycles.map((cycle) {
|
||||
final isSelected = billingCycle == cycle;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: InkWell(
|
||||
onTap: () => onChanged(cycle),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 20,
|
||||
vertical: 12,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: _getBackgroundColor(isSelected),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: _getBorder(isSelected),
|
||||
),
|
||||
child: Text(
|
||||
cycle,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: _getTextColor(isSelected),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Color _getBackgroundColor(bool isSelected) {
|
||||
if (!isSelected) {
|
||||
return isGlassmorphism
|
||||
? AppColors.backgroundColor
|
||||
: Colors.grey.withValues(alpha: 0.1);
|
||||
}
|
||||
|
||||
if (baseColor != null) {
|
||||
return baseColor!;
|
||||
}
|
||||
|
||||
if (gradientColors != null && gradientColors!.isNotEmpty) {
|
||||
return gradientColors![0];
|
||||
}
|
||||
|
||||
return const Color(0xFF3B82F6);
|
||||
}
|
||||
|
||||
Border? _getBorder(bool isSelected) {
|
||||
if (isSelected || !isGlassmorphism) {
|
||||
return null;
|
||||
}
|
||||
return Border.all(
|
||||
color: AppColors.borderColor.withValues(alpha: 0.5),
|
||||
width: 1.5,
|
||||
);
|
||||
}
|
||||
|
||||
Color _getTextColor(bool isSelected) {
|
||||
if (isSelected) {
|
||||
return Colors.white;
|
||||
}
|
||||
return isGlassmorphism
|
||||
? AppColors.darkNavy
|
||||
: Colors.grey[700]!;
|
||||
}
|
||||
}
|
||||
132
lib/widgets/common/form_fields/category_selector.dart
Normal file
132
lib/widgets/common/form_fields/category_selector.dart
Normal file
@@ -0,0 +1,132 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../theme/app_colors.dart';
|
||||
|
||||
/// 카테고리 선택 위젯
|
||||
/// 구독 서비스의 카테고리를 선택할 수 있습니다.
|
||||
class CategorySelector extends StatelessWidget {
|
||||
final List<dynamic> categories;
|
||||
final String? selectedCategoryId;
|
||||
final ValueChanged<String?> onChanged;
|
||||
final Color? baseColor;
|
||||
final List<Color>? gradientColors;
|
||||
final bool isGlassmorphism;
|
||||
|
||||
const CategorySelector({
|
||||
super.key,
|
||||
required this.categories,
|
||||
required this.selectedCategoryId,
|
||||
required this.onChanged,
|
||||
this.baseColor,
|
||||
this.gradientColors,
|
||||
this.isGlassmorphism = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: categories.map((category) {
|
||||
final isSelected = selectedCategoryId == category.id;
|
||||
return InkWell(
|
||||
onTap: () => onChanged(category.id),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 10,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: _getBackgroundColor(isSelected),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: _getBorder(isSelected),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
_getCategoryIcon(category),
|
||||
size: 18,
|
||||
color: _getTextColor(isSelected),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
category.name,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: _getTextColor(isSelected),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
IconData _getCategoryIcon(dynamic category) {
|
||||
// 카테고리명에 따른 아이콘 반환
|
||||
switch (category.name) {
|
||||
case '음악':
|
||||
return Icons.music_note_rounded;
|
||||
case 'OTT(동영상)':
|
||||
return Icons.movie_filter_rounded;
|
||||
case '저장/클라우드':
|
||||
return Icons.cloud_outlined;
|
||||
case '통신 · 인터넷 · TV':
|
||||
return Icons.wifi_rounded;
|
||||
case '생활/라이프스타일':
|
||||
return Icons.home_outlined;
|
||||
case '쇼핑/이커머스':
|
||||
return Icons.shopping_cart_outlined;
|
||||
case '프로그래밍':
|
||||
return Icons.code_rounded;
|
||||
case '협업/오피스':
|
||||
return Icons.business_center_outlined;
|
||||
case 'AI 서비스':
|
||||
return Icons.smart_toy_outlined;
|
||||
case '기타':
|
||||
default:
|
||||
return Icons.category_outlined;
|
||||
}
|
||||
}
|
||||
|
||||
Color _getBackgroundColor(bool isSelected) {
|
||||
if (!isSelected) {
|
||||
return isGlassmorphism
|
||||
? AppColors.backgroundColor
|
||||
: Colors.grey.withValues(alpha: 0.1);
|
||||
}
|
||||
|
||||
if (baseColor != null) {
|
||||
return baseColor!;
|
||||
}
|
||||
|
||||
if (gradientColors != null && gradientColors!.isNotEmpty) {
|
||||
return gradientColors![0];
|
||||
}
|
||||
|
||||
return const Color(0xFF3B82F6);
|
||||
}
|
||||
|
||||
Border? _getBorder(bool isSelected) {
|
||||
if (isSelected || !isGlassmorphism) {
|
||||
return null;
|
||||
}
|
||||
return Border.all(
|
||||
color: AppColors.borderColor.withValues(alpha: 0.5),
|
||||
width: 1.5,
|
||||
);
|
||||
}
|
||||
|
||||
Color _getTextColor(bool isSelected) {
|
||||
if (isSelected) {
|
||||
return Colors.white;
|
||||
}
|
||||
return isGlassmorphism
|
||||
? AppColors.darkNavy
|
||||
: Colors.grey[700]!;
|
||||
}
|
||||
}
|
||||
@@ -36,33 +36,62 @@ class CurrencyInputField extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _CurrencyInputFieldState extends State<CurrencyInputField> {
|
||||
late TextEditingController _formattedController;
|
||||
late FocusNode _focusNode;
|
||||
bool _isFormatted = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_formattedController = TextEditingController();
|
||||
_updateFormattedValue();
|
||||
widget.controller.addListener(_onControllerChanged);
|
||||
_focusNode = widget.focusNode ?? FocusNode();
|
||||
_focusNode.addListener(_onFocusChanged);
|
||||
|
||||
// 초기값이 있으면 포맷팅 적용
|
||||
if (widget.controller.text.isNotEmpty) {
|
||||
final value = double.tryParse(widget.controller.text.replaceAll(',', ''));
|
||||
if (value != null) {
|
||||
widget.controller.text = _formatCurrency(value);
|
||||
_isFormatted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
widget.controller.removeListener(_onControllerChanged);
|
||||
_formattedController.dispose();
|
||||
if (widget.focusNode == null) {
|
||||
_focusNode.dispose();
|
||||
} else {
|
||||
_focusNode.removeListener(_onFocusChanged);
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onControllerChanged() {
|
||||
_updateFormattedValue();
|
||||
}
|
||||
|
||||
void _updateFormattedValue() {
|
||||
final value = double.tryParse(widget.controller.text.replaceAll(',', ''));
|
||||
if (value != null) {
|
||||
_formattedController.text = _formatCurrency(value);
|
||||
} else {
|
||||
_formattedController.text = '';
|
||||
void _onFocusChanged() {
|
||||
if (!_focusNode.hasFocus && widget.controller.text.isNotEmpty) {
|
||||
// 포커스를 잃었을 때 포맷팅 적용
|
||||
final value = _parseValue(widget.controller.text);
|
||||
if (value != null) {
|
||||
setState(() {
|
||||
widget.controller.text = _formatCurrency(value);
|
||||
_isFormatted = true;
|
||||
});
|
||||
}
|
||||
} else if (_focusNode.hasFocus && _isFormatted) {
|
||||
// 포커스를 받았을 때 포맷팅 제거
|
||||
final value = _parseValue(widget.controller.text);
|
||||
if (value != null) {
|
||||
setState(() {
|
||||
if (widget.currency == 'KRW') {
|
||||
widget.controller.text = value.toInt().toString();
|
||||
} else {
|
||||
widget.controller.text = value.toString();
|
||||
}
|
||||
_isFormatted = false;
|
||||
});
|
||||
// 커서를 끝으로 이동
|
||||
widget.controller.selection = TextSelection.fromPosition(
|
||||
TextPosition(offset: widget.controller.text.length),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,38 +119,42 @@ class _CurrencyInputFieldState extends State<CurrencyInputField> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BaseTextField(
|
||||
controller: _formattedController,
|
||||
focusNode: widget.focusNode,
|
||||
controller: widget.controller,
|
||||
focusNode: _focusNode,
|
||||
label: widget.label,
|
||||
hintText: widget.hintText ?? _defaultHintText,
|
||||
textInputAction: widget.textInputAction,
|
||||
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[\d,.]')),
|
||||
FilteringTextInputFormatter.allow(
|
||||
widget.currency == 'KRW'
|
||||
? RegExp(r'[0-9]')
|
||||
: RegExp(r'[0-9.]')
|
||||
),
|
||||
if (widget.currency == 'USD')
|
||||
// USD의 경우 소수점 이하 2자리까지만 허용
|
||||
TextInputFormatter.withFunction((oldValue, newValue) {
|
||||
final text = newValue.text;
|
||||
if (text.isEmpty) return newValue;
|
||||
|
||||
final parts = text.split('.');
|
||||
if (parts.length > 2) {
|
||||
// 소수점이 2개 이상인 경우 거부
|
||||
return oldValue;
|
||||
}
|
||||
if (parts.length == 2 && parts[1].length > 2) {
|
||||
// 소수점 이하가 2자리를 초과하는 경우 거부
|
||||
return oldValue;
|
||||
}
|
||||
return newValue;
|
||||
}),
|
||||
],
|
||||
prefixText: _prefixText,
|
||||
onEditingComplete: widget.onEditingComplete,
|
||||
enabled: widget.enabled,
|
||||
onChanged: (value) {
|
||||
final parsedValue = _parseValue(value);
|
||||
if (parsedValue != null) {
|
||||
widget.controller.text = parsedValue.toString();
|
||||
widget.onChanged?.call(parsedValue);
|
||||
} else {
|
||||
widget.controller.text = '';
|
||||
widget.onChanged?.call(null);
|
||||
}
|
||||
|
||||
// 포맷팅 업데이트
|
||||
if (parsedValue != null) {
|
||||
final formattedText = _formatCurrency(parsedValue);
|
||||
if (formattedText != value) {
|
||||
_formattedController.value = TextEditingValue(
|
||||
text: formattedText,
|
||||
selection: TextSelection.collapsed(offset: formattedText.length),
|
||||
);
|
||||
}
|
||||
}
|
||||
widget.onChanged?.call(parsedValue);
|
||||
},
|
||||
validator: widget.validator ?? (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
|
||||
117
lib/widgets/common/form_fields/currency_selector.dart
Normal file
117
lib/widgets/common/form_fields/currency_selector.dart
Normal file
@@ -0,0 +1,117 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../theme/app_colors.dart';
|
||||
|
||||
/// 통화 선택 위젯
|
||||
/// KRW(원화)와 USD(달러) 중 선택할 수 있습니다.
|
||||
class CurrencySelector extends StatelessWidget {
|
||||
final String currency;
|
||||
final ValueChanged<String> onChanged;
|
||||
final bool isGlassmorphism;
|
||||
|
||||
const CurrencySelector({
|
||||
super.key,
|
||||
required this.currency,
|
||||
required this.onChanged,
|
||||
this.isGlassmorphism = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
_CurrencyOption(
|
||||
label: '₩',
|
||||
value: 'KRW',
|
||||
isSelected: currency == 'KRW',
|
||||
onTap: () => onChanged('KRW'),
|
||||
isGlassmorphism: isGlassmorphism,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
_CurrencyOption(
|
||||
label: '\$',
|
||||
value: 'USD',
|
||||
isSelected: currency == 'USD',
|
||||
onTap: () => onChanged('USD'),
|
||||
isGlassmorphism: isGlassmorphism,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 통화 옵션 버튼
|
||||
class _CurrencyOption extends StatelessWidget {
|
||||
final String label;
|
||||
final String value;
|
||||
final bool isSelected;
|
||||
final VoidCallback onTap;
|
||||
final bool isGlassmorphism;
|
||||
|
||||
const _CurrencyOption({
|
||||
required this.label,
|
||||
required this.value,
|
||||
required this.isSelected,
|
||||
required this.onTap,
|
||||
required this.isGlassmorphism,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return Expanded(
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: _getBackgroundColor(theme),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: _getBorder(),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: _getTextColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Color _getBackgroundColor(ThemeData theme) {
|
||||
if (isSelected) {
|
||||
return isGlassmorphism
|
||||
? theme.primaryColor
|
||||
: const Color(0xFF3B82F6);
|
||||
}
|
||||
return isGlassmorphism
|
||||
? AppColors.surfaceColorAlt
|
||||
: Colors.grey.withValues(alpha: 0.1);
|
||||
}
|
||||
|
||||
Border? _getBorder() {
|
||||
if (isSelected || !isGlassmorphism) {
|
||||
return null;
|
||||
}
|
||||
return Border.all(
|
||||
color: AppColors.borderColor,
|
||||
width: 1.5,
|
||||
);
|
||||
}
|
||||
|
||||
Color _getTextColor() {
|
||||
if (isSelected) {
|
||||
return Colors.white;
|
||||
}
|
||||
return isGlassmorphism
|
||||
? AppColors.navyGray
|
||||
: Colors.grey[600]!;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../../../theme/app_colors.dart';
|
||||
|
||||
/// 날짜 선택 필드 위젯
|
||||
/// 탭하면 날짜 선택기가 표시되며, 선택된 날짜를 보기 좋은 형식으로 표시합니다.
|
||||
@@ -47,7 +48,7 @@ class DatePickerField extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: theme.colorScheme.onSurface,
|
||||
color: AppColors.darkNavy,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@@ -82,10 +83,11 @@ class DatePickerField extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: contentPadding ?? const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor ?? Colors.white,
|
||||
color: backgroundColor ?? AppColors.surfaceColorAlt,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(
|
||||
color: Colors.transparent,
|
||||
color: AppColors.borderColor.withValues(alpha: 0.7),
|
||||
width: 1.5,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
@@ -96,8 +98,8 @@ class DatePickerField extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: enabled
|
||||
? theme.colorScheme.onSurface
|
||||
: theme.colorScheme.onSurface.withValues(alpha: 0.5),
|
||||
? AppColors.textPrimary
|
||||
: AppColors.textMuted,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -105,8 +107,8 @@ class DatePickerField extends StatelessWidget {
|
||||
Icons.calendar_today,
|
||||
size: 20,
|
||||
color: enabled
|
||||
? theme.colorScheme.onSurface.withValues(alpha: 0.6)
|
||||
: theme.colorScheme.onSurface.withValues(alpha: 0.3),
|
||||
? AppColors.navyGray
|
||||
: AppColors.textMuted,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -227,8 +229,12 @@ class _DateRangeItem extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: AppColors.surfaceColorAlt,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(
|
||||
color: AppColors.borderColor.withValues(alpha: 0.7),
|
||||
width: 1.5,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -237,7 +243,7 @@ class _DateRangeItem extends StatelessWidget {
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: theme.colorScheme.onSurface.withValues(alpha: 0.6),
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
@@ -249,8 +255,8 @@ class _DateRangeItem extends StatelessWidget {
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: date != null
|
||||
? theme.colorScheme.onSurface
|
||||
: theme.colorScheme.onSurface.withValues(alpha: 0.4),
|
||||
? AppColors.textPrimary
|
||||
: AppColors.textMuted,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -161,10 +161,10 @@ class AppSnackBar {
|
||||
behavior: SnackBarBehavior.floating,
|
||||
margin: showAtTop
|
||||
? EdgeInsets.only(
|
||||
top: MediaQuery.of(context).padding.top + 16,
|
||||
top: MediaQuery.of(context).padding.top,
|
||||
left: 16,
|
||||
right: 16,
|
||||
bottom: MediaQuery.of(context).size.height - 120,
|
||||
bottom: MediaQuery.of(context).size.height - 100,
|
||||
)
|
||||
: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
@@ -222,10 +222,10 @@ class AppSnackBar {
|
||||
behavior: SnackBarBehavior.floating,
|
||||
margin: showAtTop
|
||||
? EdgeInsets.only(
|
||||
top: MediaQuery.of(context).padding.top + 16,
|
||||
top: MediaQuery.of(context).padding.top,
|
||||
left: 16,
|
||||
right: 16,
|
||||
bottom: MediaQuery.of(context).size.height - 120,
|
||||
bottom: MediaQuery.of(context).size.height - 100,
|
||||
)
|
||||
: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
|
||||
Reference in New Issue
Block a user