285 lines
9.0 KiB
Dart
285 lines
9.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:intl/intl.dart';
|
|
// import '../../../theme/app_colors.dart';
|
|
import '../../../l10n/app_localizations.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 localizations = AppLocalizations.of(context);
|
|
final effectiveDateFormat = dateFormat ?? localizations.dateFormatFull;
|
|
final locale = Localizations.localeOf(context);
|
|
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
label,
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w600,
|
|
color: Theme.of(context).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) {
|
|
final cs = Theme.of(context).colorScheme;
|
|
return Theme(
|
|
data: Theme.of(context).copyWith(
|
|
colorScheme: cs.copyWith(
|
|
primary: effectivePrimaryColor,
|
|
onPrimary: cs.onPrimary,
|
|
surface: cs.surface,
|
|
onSurface: cs.onSurface,
|
|
),
|
|
),
|
|
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 ?? Theme.of(context).colorScheme.surface,
|
|
borderRadius: BorderRadius.circular(16),
|
|
border: Border.all(
|
|
color: Theme.of(context)
|
|
.colorScheme
|
|
.outline
|
|
.withValues(alpha: 0.6),
|
|
width: 1.5,
|
|
),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: Text(
|
|
DateFormat(effectiveDateFormat, locale.toString())
|
|
.format(selectedDate),
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
color: enabled
|
|
? Theme.of(context).colorScheme.onSurface
|
|
: Theme.of(context).colorScheme.onSurfaceVariant,
|
|
),
|
|
),
|
|
),
|
|
Icon(
|
|
Icons.calendar_today,
|
|
size: 20,
|
|
color: enabled
|
|
? Theme.of(context).colorScheme.onSurfaceVariant
|
|
: Theme.of(context).colorScheme.onSurfaceVariant,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 날짜 범위 선택 필드 위젯
|
|
/// 시작일과 종료일을 선택할 수 있는 필드입니다.
|
|
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) {
|
|
final cs = Theme.of(context).colorScheme;
|
|
return Theme(
|
|
data: Theme.of(context).copyWith(
|
|
colorScheme: cs.copyWith(
|
|
primary: effectivePrimaryColor,
|
|
onPrimary: cs.onPrimary,
|
|
surface: cs.surface,
|
|
onSurface: cs.onSurface,
|
|
),
|
|
),
|
|
child: child!,
|
|
);
|
|
},
|
|
);
|
|
|
|
if (picked != null) {
|
|
onDateSelected(picked);
|
|
}
|
|
}
|
|
: null,
|
|
borderRadius: BorderRadius.circular(16),
|
|
child: Container(
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
color: Theme.of(context).colorScheme.surface,
|
|
borderRadius: BorderRadius.circular(16),
|
|
border: Border.all(
|
|
color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.6),
|
|
width: 1.5,
|
|
),
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
label,
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
date != null
|
|
? DateFormat(AppLocalizations.of(context).dateFormatShort)
|
|
.format(date!)
|
|
: AppLocalizations.of(context).dateSelect,
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w500,
|
|
color: date != null
|
|
? Theme.of(context).colorScheme.onSurface
|
|
: Theme.of(context).colorScheme.onSurfaceVariant,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|