339 lines
10 KiB
Dart
339 lines
10 KiB
Dart
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../../../models/day_time.dart';
|
|
import '../../../utils/date_time.dart';
|
|
|
|
class CustomCupertinoDatePicker extends StatefulWidget {
|
|
final double itemExtent;
|
|
final void Function(DayTime)
|
|
onSelectedItemChanged; // Text style of selected item
|
|
final TextStyle? selectedStyle; // Text style of unselected item
|
|
final TextStyle? unselectedStyle; // Text style of disabled item
|
|
final TextStyle? disabledStyle; // Minimum selectable date
|
|
final DayTime? selectedTime;
|
|
final bool disable;
|
|
|
|
const CustomCupertinoDatePicker({
|
|
Key? key,
|
|
required this.itemExtent,
|
|
required this.onSelectedItemChanged,
|
|
this.selectedTime,
|
|
this.selectedStyle,
|
|
this.unselectedStyle,
|
|
this.disabledStyle,
|
|
this.disable = false,
|
|
}) : super(key: key);
|
|
|
|
@override
|
|
State<CustomCupertinoDatePicker> createState() =>
|
|
_CustomCupertinoDatePickerState();
|
|
}
|
|
|
|
class _CustomCupertinoDatePickerState extends State<CustomCupertinoDatePicker> {
|
|
late DayTime selectedTime = DateTimeUtils.handleDayTime(
|
|
"${DateTime.now().hour.toString()}:${DateTime.now().minute.toString()}");
|
|
|
|
late int _selectedMeridiemIndex;
|
|
late int _selectedHourIndex;
|
|
late int _selectedMinuteIndex;
|
|
|
|
late final FixedExtentScrollController _meridiemScrollController;
|
|
late final FixedExtentScrollController _hourScrollController;
|
|
late final FixedExtentScrollController _minuteScrollController;
|
|
|
|
final _meridiem = [
|
|
'قبل از ظهر',
|
|
'بعد از ظهر',
|
|
];
|
|
|
|
final _timeH = [];
|
|
|
|
final _timeM = [];
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
for (int i = 0; i < 12 + 1; i++) {
|
|
String twoDigitNumber = i.toString().padLeft(2, '0');
|
|
_timeH.add(twoDigitNumber);
|
|
}
|
|
for (int i = 1; i < 11 + 1; i++) {
|
|
String twoDigitNumber = i.toString().padLeft(2, '0');
|
|
_timeH.add(twoDigitNumber);
|
|
}
|
|
for (int i = 0; i < 59 + 1; i++) {
|
|
String twoDigitNumber = i.toString().padLeft(2, '0');
|
|
_timeM.add(twoDigitNumber);
|
|
}
|
|
_meridiemScrollController = FixedExtentScrollController();
|
|
_hourScrollController = FixedExtentScrollController();
|
|
_minuteScrollController = FixedExtentScrollController();
|
|
if (widget.selectedTime != null) {
|
|
selectedTime = widget.selectedTime!;
|
|
}
|
|
_initDates();
|
|
}
|
|
|
|
void _initDates() {
|
|
_selectedMeridiemIndex = 0;
|
|
|
|
switch (selectedTime.meridiem) {
|
|
case Meridiem.AM:
|
|
_selectedMeridiemIndex = 0;
|
|
_selectedHourIndex = int.parse(selectedTime.hour) - 1;
|
|
|
|
break;
|
|
|
|
case Meridiem.PM:
|
|
_selectedMeridiemIndex = 1;
|
|
_selectedHourIndex = (int.parse(selectedTime.hour) + 12) - 1;
|
|
|
|
break;
|
|
}
|
|
_selectedMinuteIndex = int.parse(selectedTime.minute);
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
_scrollList(_meridiemScrollController, _selectedMeridiemIndex);
|
|
_scrollList(_hourScrollController, _selectedHourIndex);
|
|
_scrollList(_minuteScrollController, _selectedMinuteIndex);
|
|
});
|
|
}
|
|
|
|
void _scrollList(FixedExtentScrollController controller, int index) {
|
|
controller.animateToItem(
|
|
index,
|
|
curve: Curves.easeIn,
|
|
duration: const Duration(milliseconds: 300),
|
|
);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_meridiemScrollController.dispose();
|
|
_hourScrollController.dispose();
|
|
_minuteScrollController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
void _onSelectedItemChanged(int index, SelectorType type) {
|
|
switch (type) {
|
|
case SelectorType.meridiem:
|
|
_selectedMeridiemIndex = index; // if month is changed to february &
|
|
if (_selectedMeridiemIndex == 0) {
|
|
if (_selectedHourIndex > 12 - 1) {
|
|
_selectedHourIndex -= 12;
|
|
_hourScrollController.jumpToItem(_selectedHourIndex);
|
|
}
|
|
} else {
|
|
if (_selectedHourIndex < 12 - 1) {
|
|
_selectedHourIndex += 12;
|
|
_hourScrollController.jumpToItem(_selectedHourIndex);
|
|
}
|
|
}
|
|
if (index == 0) {
|
|
selectedTime.meridiem = Meridiem.AM;
|
|
} else {
|
|
selectedTime.meridiem = Meridiem.PM;
|
|
}
|
|
break;
|
|
|
|
case SelectorType.hour:
|
|
_selectedHourIndex = index; // if month is changed to february &
|
|
if (_selectedHourIndex > 12 - 1) {
|
|
_selectedMeridiemIndex = 1;
|
|
_meridiemScrollController.jumpToItem(_selectedMeridiemIndex);
|
|
} else {
|
|
_selectedMeridiemIndex = 0;
|
|
_meridiemScrollController.jumpToItem(_selectedMeridiemIndex);
|
|
}
|
|
selectedTime.hour = _timeH[index];
|
|
|
|
break;
|
|
|
|
case SelectorType.minute:
|
|
_selectedMinuteIndex = index;
|
|
selectedTime.minute = _timeM[index];
|
|
|
|
break;
|
|
}
|
|
|
|
setState(() {});
|
|
widget.onSelectedItemChanged(selectedTime);
|
|
}
|
|
|
|
/// check if the given day, month or year index is disabled
|
|
bool _isDisabled(int index, SelectorType type) {
|
|
// switch (type) {
|
|
// case SelectorType.meridiem:
|
|
// break;
|
|
//
|
|
// case SelectorType.hour:
|
|
// break;
|
|
//
|
|
// case SelectorType.minute:
|
|
// break;
|
|
// }
|
|
return false;
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
Color shadow = Theme.of(context).colorScheme.background;
|
|
return IgnorePointer(
|
|
ignoring: widget.disable,
|
|
child: Stack(
|
|
children: [
|
|
Positioned.fill(
|
|
child: Center(
|
|
child: Container(
|
|
height: 64,
|
|
decoration: BoxDecoration(
|
|
color: Theme.of(context)
|
|
.colorScheme
|
|
.primary
|
|
.withOpacity(widget.disable ? 0.2 : 1),
|
|
borderRadius: BorderRadius.circular(18)),
|
|
child: const Padding(
|
|
padding: EdgeInsets.symmetric(vertical: 12),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: [
|
|
SizedBox(),
|
|
VerticalDivider(
|
|
color: Colors.white,
|
|
),
|
|
VerticalDivider(
|
|
color: Colors.white,
|
|
),
|
|
SizedBox(),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
Row(
|
|
children: [
|
|
Expanded(child: _meridiemSelector()),
|
|
Expanded(child: _minuteSelector()),
|
|
Expanded(child: _hourSelector()),
|
|
],
|
|
),
|
|
Positioned(
|
|
top: 0,
|
|
left: 0,
|
|
right: 0,
|
|
child: Container(
|
|
height: 32,
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: [
|
|
shadow.withOpacity(1),
|
|
shadow.withOpacity(0.9),
|
|
shadow.withOpacity(0.8),
|
|
shadow.withOpacity(0.6),
|
|
shadow.withOpacity(0.5),
|
|
shadow.withOpacity(0.4),
|
|
])),
|
|
)),
|
|
Positioned(
|
|
bottom: 0,
|
|
left: 0,
|
|
right: 0,
|
|
child: Container(
|
|
height: 32,
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.bottomCenter,
|
|
end: Alignment.topCenter,
|
|
colors: [
|
|
shadow.withOpacity(1),
|
|
shadow.withOpacity(0.9),
|
|
shadow.withOpacity(0.8),
|
|
shadow.withOpacity(0.6),
|
|
shadow.withOpacity(0.5),
|
|
shadow.withOpacity(0.4),
|
|
])),
|
|
)),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _selector({
|
|
required List<dynamic> values,
|
|
required int selectedValueIndex,
|
|
required bool Function(int) isDisabled,
|
|
required void Function(int) onSelectedItemChanged,
|
|
required FixedExtentScrollController scrollController,
|
|
}) {
|
|
return CupertinoPicker.builder(
|
|
childCount: values.length,
|
|
itemExtent: widget.itemExtent,
|
|
scrollController: scrollController,
|
|
squeeze: 1.45,
|
|
useMagnifier: false,
|
|
diameterRatio: 2.3,
|
|
magnification: 1.0,
|
|
offAxisFraction: 0.0,
|
|
selectionOverlay: const SizedBox(),
|
|
onSelectedItemChanged: onSelectedItemChanged,
|
|
itemBuilder: (context, index) => Container(
|
|
height: widget.itemExtent,
|
|
alignment: Alignment.center,
|
|
decoration: const BoxDecoration(),
|
|
child: Text(
|
|
'${values[index]}',
|
|
style: index == selectedValueIndex
|
|
? widget.selectedStyle
|
|
: isDisabled(index)
|
|
? widget.disabledStyle
|
|
: widget.unselectedStyle,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _meridiemSelector() {
|
|
return _selector(
|
|
values: _meridiem,
|
|
selectedValueIndex: _selectedMeridiemIndex,
|
|
scrollController: _meridiemScrollController,
|
|
isDisabled: (index) => _isDisabled(index, SelectorType.meridiem),
|
|
onSelectedItemChanged: (v) => _onSelectedItemChanged(
|
|
v,
|
|
SelectorType.meridiem,
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _hourSelector() {
|
|
return _selector(
|
|
values: _timeH,
|
|
selectedValueIndex: _selectedHourIndex,
|
|
scrollController: _hourScrollController,
|
|
isDisabled: (index) => _isDisabled(index, SelectorType.hour),
|
|
onSelectedItemChanged: (v) => _onSelectedItemChanged(
|
|
v,
|
|
SelectorType.hour,
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _minuteSelector() {
|
|
return _selector(
|
|
values: _timeM,
|
|
selectedValueIndex: _selectedMinuteIndex,
|
|
scrollController: _minuteScrollController,
|
|
isDisabled: (index) => _isDisabled(index, SelectorType.minute),
|
|
onSelectedItemChanged: (v) => _onSelectedItemChanged(
|
|
v,
|
|
SelectorType.minute,
|
|
),
|
|
);
|
|
}
|
|
}
|