Files
submanager/lib/widgets/common/form_fields/date_picker_field.dart
JiWoong Sul 2f60ef585a feat: 글래스모피즘 디자인 시스템 및 색상 가이드 전면 적용
- @doc/color.md 가이드라인에 따른 색상 시스템 전면 개편
- 딥 블루(#2563EB), 스카이 블루(#60A5FA) 메인 컬러로 변경
- 모든 화면과 위젯에 글래스모피즘 효과 일관성 있게 적용
- darkNavy, navyGray 등 새로운 텍스트 색상 체계 도입
- 공통 스낵바 및 다이얼로그 컴포넌트 추가
- Claude AI 프로젝트 컨텍스트 파일(CLAUDE.md) 추가

영향받은 컴포넌트:
- 10개 스크린 (main, settings, detail, splash 등)
- 30개 이상 위젯 (buttons, cards, forms 등)
- 테마 시스템 (AppColors, AppTheme)

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-11 18:41:05 +09:00

261 lines
7.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
/// 날짜 선택 필드 위젯
/// 탭하면 날짜 선택기가 표시되며, 선택된 날짜를 보기 좋은 형식으로 표시합니다.
class DatePickerField extends StatelessWidget {
final DateTime selectedDate;
final Function(DateTime) onDateSelected;
final String label;
final String? hintText;
final DateTime? firstDate;
final DateTime? lastDate;
final bool enabled;
final FocusNode? focusNode;
final Color? backgroundColor;
final EdgeInsetsGeometry? contentPadding;
final String? dateFormat;
final Color? primaryColor;
const DatePickerField({
super.key,
required this.selectedDate,
required this.onDateSelected,
required this.label,
this.hintText,
this.firstDate,
this.lastDate,
this.enabled = true,
this.focusNode,
this.backgroundColor,
this.contentPadding,
this.dateFormat,
this.primaryColor,
});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final effectivePrimaryColor = primaryColor ?? theme.primaryColor;
final effectiveDateFormat = dateFormat ?? 'yyyy년 MM월 dd일';
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: theme.colorScheme.onSurface,
),
),
const SizedBox(height: 8),
InkWell(
focusNode: focusNode,
onTap: enabled ? () async {
final DateTime? picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: firstDate ?? DateTime.now().subtract(const Duration(days: 365 * 10)),
lastDate: lastDate ?? DateTime.now().add(const Duration(days: 365 * 10)),
builder: (BuildContext context, Widget? child) {
return Theme(
data: ThemeData.light().copyWith(
colorScheme: ColorScheme.light(
primary: effectivePrimaryColor,
onPrimary: Colors.white,
surface: Colors.white,
onSurface: Colors.black,
),
),
child: child!,
);
},
);
if (picked != null && picked != selectedDate) {
onDateSelected(picked);
}
} : null,
borderRadius: BorderRadius.circular(16),
child: Container(
padding: contentPadding ?? const EdgeInsets.all(16),
decoration: BoxDecoration(
color: backgroundColor ?? Colors.white,
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: Colors.transparent,
),
),
child: Row(
children: [
Expanded(
child: Text(
DateFormat(effectiveDateFormat).format(selectedDate),
style: TextStyle(
fontSize: 16,
color: enabled
? theme.colorScheme.onSurface
: theme.colorScheme.onSurface.withValues(alpha: 0.5),
),
),
),
Icon(
Icons.calendar_today,
size: 20,
color: enabled
? theme.colorScheme.onSurface.withValues(alpha: 0.6)
: theme.colorScheme.onSurface.withValues(alpha: 0.3),
),
],
),
),
),
],
);
}
}
/// 날짜 범위 선택 필드 위젯
/// 시작일과 종료일을 선택할 수 있는 필드입니다.
class DateRangePickerField extends StatelessWidget {
final DateTime? startDate;
final DateTime? endDate;
final Function(DateTime?) onStartDateSelected;
final Function(DateTime?) onEndDateSelected;
final String startLabel;
final String endLabel;
final bool enabled;
final Color? primaryColor;
const DateRangePickerField({
super.key,
required this.startDate,
required this.endDate,
required this.onStartDateSelected,
required this.onEndDateSelected,
this.startLabel = '시작일',
this.endLabel = '종료일',
this.enabled = true,
this.primaryColor,
});
@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: _DateRangeItem(
date: startDate,
label: startLabel,
enabled: enabled,
primaryColor: primaryColor,
onDateSelected: onStartDateSelected,
firstDate: DateTime.now().subtract(const Duration(days: 365)),
lastDate: endDate ?? DateTime.now().add(const Duration(days: 365 * 2)),
),
),
const SizedBox(width: 12),
Expanded(
child: _DateRangeItem(
date: endDate,
label: endLabel,
enabled: enabled && startDate != null,
primaryColor: primaryColor,
onDateSelected: onEndDateSelected,
firstDate: startDate ?? DateTime.now(),
lastDate: DateTime.now().add(const Duration(days: 365 * 2)),
),
),
],
);
}
}
class _DateRangeItem extends StatelessWidget {
final DateTime? date;
final String label;
final bool enabled;
final Color? primaryColor;
final Function(DateTime?) onDateSelected;
final DateTime firstDate;
final DateTime lastDate;
const _DateRangeItem({
required this.date,
required this.label,
required this.enabled,
required this.primaryColor,
required this.onDateSelected,
required this.firstDate,
required this.lastDate,
});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final effectivePrimaryColor = primaryColor ?? theme.primaryColor;
return InkWell(
onTap: enabled ? () async {
final DateTime? picked = await showDatePicker(
context: context,
initialDate: date ?? DateTime.now(),
firstDate: firstDate,
lastDate: lastDate,
builder: (BuildContext context, Widget? child) {
return Theme(
data: ThemeData.light().copyWith(
colorScheme: ColorScheme.light(
primary: effectivePrimaryColor,
onPrimary: Colors.white,
surface: Colors.white,
onSurface: Colors.black,
),
),
child: child!,
);
},
);
if (picked != null) {
onDateSelected(picked);
}
} : null,
borderRadius: BorderRadius.circular(16),
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 12,
color: theme.colorScheme.onSurface.withValues(alpha: 0.6),
),
),
const SizedBox(height: 4),
Text(
date != null
? DateFormat('MM/dd').format(date!)
: '선택',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: date != null
? theme.colorScheme.onSurface
: theme.colorScheme.onSurface.withValues(alpha: 0.4),
),
),
],
),
),
);
}
}