mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-09 22:57:21 +00:00
738 lines
25 KiB
Dart
738 lines
25 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:flutter_svg/flutter_svg.dart';
|
|
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
|
import 'package:syncrow_web/pages/device_managment/water_heater/bloc/water_heater_bloc.dart';
|
|
import 'package:syncrow_web/pages/device_managment/water_heater/models/schedule_entry.dart';
|
|
import 'package:syncrow_web/pages/device_managment/water_heater/models/water_heater_status_model.dart';
|
|
import 'package:syncrow_web/utils/color_manager.dart';
|
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
|
|
class BuildScheduleView extends StatefulWidget {
|
|
const BuildScheduleView({super.key, required this.status});
|
|
|
|
final WaterHeaterStatusModel status;
|
|
|
|
@override
|
|
_BuildScheduleViewState createState() => _BuildScheduleViewState();
|
|
}
|
|
|
|
class _BuildScheduleViewState extends State<BuildScheduleView> {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final bloc = BlocProvider.of<WaterHeaterBloc>(context);
|
|
return BlocProvider.value(
|
|
value: bloc,
|
|
child: Dialog(
|
|
backgroundColor: Colors.white,
|
|
insetPadding: const EdgeInsets.all(20),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(20),
|
|
),
|
|
child: SizedBox(
|
|
width: 700,
|
|
child: SingleChildScrollView(
|
|
child: Padding(
|
|
padding:
|
|
const EdgeInsets.symmetric(horizontal: 40.0, vertical: 20),
|
|
child: BlocBuilder<WaterHeaterBloc, WaterHeaterState>(
|
|
builder: (context, state) {
|
|
if (state is WaterHeaterDeviceStatusLoaded) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
_scheduleHeader(context),
|
|
const SizedBox(height: 20),
|
|
_buildScheduleModeSelector(context, state),
|
|
const SizedBox(height: 20),
|
|
if (state.scheduleMode == ScheduleModes.schedule)
|
|
_buildScheduleManagementUI(state),
|
|
if (state.scheduleMode == ScheduleModes.countdown ||
|
|
state.scheduleMode == ScheduleModes.inching)
|
|
..._buildCountDownAngInchingView(context, state),
|
|
const SizedBox(height: 20),
|
|
_buildSaveStopCancelButtons(context, state),
|
|
],
|
|
);
|
|
}
|
|
return const SizedBox();
|
|
},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Row _scheduleHeader(BuildContext context) {
|
|
return Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
const SizedBox(),
|
|
Text(
|
|
'Scheduling',
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 22,
|
|
color: ColorsManager.dialogBlueTitle,
|
|
),
|
|
),
|
|
Container(
|
|
width: 25,
|
|
decoration: BoxDecoration(
|
|
color: Colors.transparent,
|
|
shape: BoxShape.circle,
|
|
border: Border.all(
|
|
color: Colors.grey,
|
|
width: 1.0,
|
|
),
|
|
),
|
|
child: IconButton(
|
|
padding: EdgeInsets.all(1),
|
|
icon: const Icon(
|
|
Icons.close,
|
|
color: Colors.grey,
|
|
size: 18,
|
|
),
|
|
onPressed: () {
|
|
Navigator.of(context).pop();
|
|
},
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildScheduleModeSelector(
|
|
BuildContext context, WaterHeaterDeviceStatusLoaded state) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'Type:',
|
|
style: context.textTheme.bodySmall!.copyWith(
|
|
fontSize: 13,
|
|
color: ColorsManager.grayColor,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
children: [
|
|
_buildRadioTile(
|
|
context, 'Countdown', ScheduleModes.countdown, state),
|
|
_buildRadioTile(context, 'Schedule', ScheduleModes.schedule, state),
|
|
_buildRadioTile(
|
|
context, 'Circulate', ScheduleModes.circulate, state),
|
|
_buildRadioTile(context, 'Inching', ScheduleModes.inching, state),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildRadioTile(BuildContext context, String label, ScheduleModes mode,
|
|
WaterHeaterDeviceStatusLoaded state) {
|
|
return Flexible(
|
|
child: ListTile(
|
|
contentPadding: EdgeInsets.zero,
|
|
title: Text(
|
|
label,
|
|
style: context.textTheme.bodySmall!.copyWith(
|
|
fontSize: 13,
|
|
color: ColorsManager.blackColor,
|
|
),
|
|
),
|
|
leading: Radio<ScheduleModes>(
|
|
value: mode,
|
|
groupValue: state.scheduleMode,
|
|
onChanged: (ScheduleModes? value) {
|
|
if (value != null) {
|
|
context.read<WaterHeaterBloc>().add(UpdateScheduleEvent(
|
|
scheduleMode: value,
|
|
hours: state.hours ?? 0,
|
|
minutes: state.minutes ?? 0,
|
|
));
|
|
}
|
|
},
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildScheduleManagementUI(WaterHeaterDeviceStatusLoaded state) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
SizedBox(
|
|
width: 170,
|
|
height: 40,
|
|
child: DefaultButton(
|
|
borderColor: ColorsManager.boxColor,
|
|
padding: 2,
|
|
backgroundColor: ColorsManager.graysColor,
|
|
borderRadius: 15,
|
|
onPressed: () =>
|
|
_showAddScheduleDialog(context, schedule: null, index: null),
|
|
child: Row(
|
|
children: [
|
|
const Icon(Icons.add, color: ColorsManager.primaryColor),
|
|
Text(
|
|
' Add new schedule',
|
|
style: context.textTheme.bodySmall!.copyWith(
|
|
color: ColorsManager.blackColor,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 20),
|
|
_buildScheduleTable(state),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildScheduleTable(WaterHeaterDeviceStatusLoaded state) {
|
|
return Column(
|
|
children: [
|
|
Table(
|
|
border: TableBorder.all(
|
|
color: ColorsManager.graysColor,
|
|
borderRadius: const BorderRadius.only(
|
|
topLeft: Radius.circular(20), topRight: Radius.circular(20)),
|
|
),
|
|
children: [
|
|
TableRow(
|
|
decoration: const BoxDecoration(
|
|
color: ColorsManager.boxColor,
|
|
borderRadius: BorderRadius.only(
|
|
topLeft: Radius.circular(20),
|
|
topRight: Radius.circular(20),
|
|
),
|
|
),
|
|
children: [
|
|
_buildTableHeader('Active'),
|
|
_buildTableHeader('Days'),
|
|
_buildTableHeader('Time'),
|
|
_buildTableHeader('Function'),
|
|
_buildTableHeader('Action'),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
Container(
|
|
height: 200,
|
|
decoration: BoxDecoration(
|
|
border: Border.all(color: ColorsManager.graysColor),
|
|
borderRadius: const BorderRadius.only(
|
|
bottomLeft: Radius.circular(20),
|
|
bottomRight: Radius.circular(20)),
|
|
),
|
|
child: state.schedules.isEmpty
|
|
? _buildEmptyState(context)
|
|
: _buildTableBody(state),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildEmptyState(BuildContext context) {
|
|
return Center(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
SvgPicture.asset(Assets.emptyRecords, width: 40, height: 40),
|
|
const SizedBox(height: 8),
|
|
Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Text(
|
|
'No schedules added yet',
|
|
style: context.textTheme.bodySmall!.copyWith(
|
|
fontSize: 13,
|
|
color: ColorsManager.grayColor,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildTableBody(WaterHeaterDeviceStatusLoaded state) {
|
|
return SingleChildScrollView(
|
|
child: Table(
|
|
border: TableBorder.all(color: ColorsManager.graysColor),
|
|
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
|
children: [
|
|
for (int i = 0; i < state.schedules.length; i++)
|
|
_buildScheduleRow(state.schedules[i], i, context),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
TableRow _buildScheduleRow(
|
|
ScheduleEntry schedule, int index, BuildContext context) {
|
|
return TableRow(
|
|
children: [
|
|
Center(
|
|
child: schedule.functionOn
|
|
? const Icon(Icons.radio_button_checked,
|
|
color: ColorsManager.blueColor)
|
|
: const Icon(Icons.radio_button_unchecked)),
|
|
Center(child: Text(_getSelectedDays(schedule.selectedDays))),
|
|
Center(child: Text(schedule.time.format(context))),
|
|
Center(child: Text(schedule.functionOn ? 'On' : 'Off')),
|
|
Center(
|
|
child: Wrap(
|
|
runAlignment: WrapAlignment.center,
|
|
children: [
|
|
TextButton(
|
|
style: TextButton.styleFrom(padding: EdgeInsets.zero),
|
|
onPressed: () {
|
|
_showAddScheduleDialog(context,
|
|
schedule: schedule, index: index);
|
|
},
|
|
child: Text(
|
|
'Edit',
|
|
style: context.textTheme.bodySmall!
|
|
.copyWith(color: ColorsManager.blueColor),
|
|
),
|
|
),
|
|
TextButton(
|
|
style: TextButton.styleFrom(padding: EdgeInsets.zero),
|
|
onPressed: () {
|
|
context
|
|
.read<WaterHeaterBloc>()
|
|
.add(DeleteScheduleEvent(index));
|
|
},
|
|
child: Text(
|
|
'Delete',
|
|
style: context.textTheme.bodySmall!
|
|
.copyWith(color: ColorsManager.blueColor),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
String _getSelectedDays(List<bool> selectedDays) {
|
|
final days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
|
|
List<String> selectedDaysStr = [];
|
|
for (int i = 0; i < selectedDays.length; i++) {
|
|
if (selectedDays[i]) {
|
|
selectedDaysStr.add(days[i]);
|
|
}
|
|
}
|
|
return selectedDaysStr.join(', ');
|
|
}
|
|
|
|
Widget _buildTableHeader(String label) {
|
|
return TableCell(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(12),
|
|
child: Text(
|
|
label,
|
|
style: context.textTheme.bodySmall!.copyWith(
|
|
fontSize: 13,
|
|
color: ColorsManager.grayColor,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
void _showAddScheduleDialog(BuildContext context,
|
|
{ScheduleEntry? schedule, int? index}) {
|
|
final bloc = context.read<WaterHeaterBloc>();
|
|
|
|
if (schedule != null) {
|
|
bloc.add(InitializeAddScheduleEvent(
|
|
selectedTime: schedule.time,
|
|
selectedDays: schedule.selectedDays,
|
|
functionOn: schedule.functionOn,
|
|
isEditing: true,
|
|
index: index,
|
|
));
|
|
} else {
|
|
bloc.add(
|
|
const InitializeAddScheduleEvent(
|
|
selectedDays: [false, false, false, false, false, false, false],
|
|
functionOn: false,
|
|
isEditing: false,
|
|
index: null,
|
|
selectedTime: null,
|
|
),
|
|
);
|
|
}
|
|
|
|
showDialog(
|
|
context: context,
|
|
builder: (ctx) {
|
|
return BlocProvider.value(
|
|
value: bloc,
|
|
child: BlocBuilder<WaterHeaterBloc, WaterHeaterState>(
|
|
builder: (context, state) {
|
|
if (state is WaterHeaterDeviceStatusLoaded) {
|
|
return AlertDialog(
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(20),
|
|
),
|
|
content: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
const SizedBox(),
|
|
Text(
|
|
'Scheduling',
|
|
style: context.textTheme.titleLarge!.copyWith(
|
|
color: ColorsManager.dialogBlueTitle,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
const SizedBox(),
|
|
],
|
|
),
|
|
const SizedBox(height: 24),
|
|
SizedBox(
|
|
width: 150,
|
|
height: 40,
|
|
child: DefaultButton(
|
|
padding: 8,
|
|
backgroundColor: ColorsManager.boxColor,
|
|
borderRadius: 15,
|
|
onPressed: () async {
|
|
TimeOfDay? time = await showTimePicker(
|
|
context: context,
|
|
initialTime:
|
|
state.selectedTime ?? TimeOfDay.now(),
|
|
);
|
|
if (time != null) {
|
|
bloc.add(UpdateSelectedTimeEvent(time));
|
|
}
|
|
},
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(
|
|
state.selectedTime == null
|
|
? 'Time'
|
|
: state.selectedTime!.format(context),
|
|
style: context.textTheme.bodySmall!.copyWith(
|
|
color: ColorsManager.grayColor,
|
|
),
|
|
),
|
|
const Icon(
|
|
Icons.access_time,
|
|
color: ColorsManager.grayColor,
|
|
size: 18,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
_buildDayCheckboxes(context, state.selectedDays),
|
|
const SizedBox(height: 16),
|
|
_buildFunctionSwitch(context, state.functionOn),
|
|
],
|
|
),
|
|
actions: [
|
|
SizedBox(
|
|
width: 200,
|
|
child: DefaultButton(
|
|
height: 40,
|
|
onPressed: () {
|
|
Navigator.pop(context);
|
|
},
|
|
backgroundColor: ColorsManager.boxColor,
|
|
child: Text(
|
|
'Cancel',
|
|
style: context.textTheme.bodyMedium,
|
|
),
|
|
),
|
|
),
|
|
SizedBox(
|
|
width: 200,
|
|
child: DefaultButton(
|
|
height: 40,
|
|
onPressed: () {
|
|
if (state.selectedTime != null) {
|
|
if (state.isEditing && index != null) {
|
|
bloc.add(UpdateScheduleEntryEvent(
|
|
deviceId: state.status.uuid,
|
|
category: 'kg',
|
|
functionOn: state.functionOn,
|
|
));
|
|
} else {
|
|
bloc.add(AddScheduleEvent(
|
|
category: 'kg',
|
|
time: state.selectedTime!,
|
|
selectedDays: state.selectedDays,
|
|
functionOn: state.functionOn,
|
|
));
|
|
}
|
|
Navigator.pop(context);
|
|
}
|
|
},
|
|
backgroundColor: ColorsManager.primaryColor,
|
|
child: const Text('Save'),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
return const SizedBox();
|
|
},
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Widget _buildDayCheckboxes(BuildContext context, List<bool> selectedDays) {
|
|
return Row(
|
|
children: List.generate(7, (index) {
|
|
final dayLabels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
|
|
return Row(
|
|
children: [
|
|
Checkbox(
|
|
value: selectedDays[index],
|
|
onChanged: (bool? value) {
|
|
context
|
|
.read<WaterHeaterBloc>()
|
|
.add(UpdateSelectedDayEvent(index, value!));
|
|
},
|
|
),
|
|
Text(dayLabels[index]),
|
|
],
|
|
);
|
|
}),
|
|
);
|
|
}
|
|
|
|
Widget _buildFunctionSwitch(BuildContext context, bool isOn) {
|
|
return Row(
|
|
children: [
|
|
Text(
|
|
'Function:',
|
|
style: context.textTheme.bodySmall!
|
|
.copyWith(color: ColorsManager.grayColor),
|
|
),
|
|
const SizedBox(width: 10),
|
|
Radio<bool>(
|
|
value: true,
|
|
groupValue: isOn,
|
|
onChanged: (bool? value) {
|
|
context
|
|
.read<WaterHeaterBloc>()
|
|
.add(const UpdateFunctionOnEvent(true));
|
|
},
|
|
),
|
|
const Text('On'),
|
|
const SizedBox(width: 10),
|
|
Radio<bool>(
|
|
value: false,
|
|
groupValue: isOn,
|
|
onChanged: (bool? value) {
|
|
context
|
|
.read<WaterHeaterBloc>()
|
|
.add(const UpdateFunctionOnEvent(false));
|
|
},
|
|
),
|
|
const Text('Off'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Center _buildSaveStopCancelButtons(
|
|
BuildContext context, WaterHeaterDeviceStatusLoaded state) {
|
|
return Center(
|
|
child: SizedBox(
|
|
width: 400,
|
|
height: 50,
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
mainAxisSize: MainAxisSize.max,
|
|
children: [
|
|
Expanded(
|
|
child: DefaultButton(
|
|
height: 40,
|
|
onPressed: () {
|
|
Navigator.pop(context);
|
|
},
|
|
backgroundColor: ColorsManager.boxColor,
|
|
child: Text(
|
|
'Cancel',
|
|
style: context.textTheme.bodyMedium,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(width: 20),
|
|
Expanded(
|
|
child:
|
|
(state.countdownRemaining != null && state.isActive == true)
|
|
? DefaultButton(
|
|
height: 40,
|
|
onPressed: () {
|
|
late String code;
|
|
if (state.scheduleMode == ScheduleModes.countdown) {
|
|
code = 'countdown_1';
|
|
} else if (state.scheduleMode ==
|
|
ScheduleModes.inching) {
|
|
code = 'switch_inching';
|
|
}
|
|
context
|
|
.read<WaterHeaterBloc>()
|
|
.add(StopScheduleEvent(widget.status.uuid));
|
|
context.read<WaterHeaterBloc>().add(
|
|
ToggleWaterHeaterEvent(
|
|
deviceId: widget.status.uuid,
|
|
code: code,
|
|
value: 0,
|
|
),
|
|
);
|
|
},
|
|
backgroundColor: Colors.red,
|
|
child: const Text('Stop'),
|
|
)
|
|
: DefaultButton(
|
|
height: 40,
|
|
onPressed: () {
|
|
late String code;
|
|
if (state.scheduleMode == ScheduleModes.countdown) {
|
|
code = 'countdown_1';
|
|
} else if (state.scheduleMode ==
|
|
ScheduleModes.inching) {
|
|
code = 'switch_inching';
|
|
}
|
|
context.read<WaterHeaterBloc>().add(
|
|
ToggleWaterHeaterEvent(
|
|
deviceId: widget.status.uuid,
|
|
code: code,
|
|
value: Duration(
|
|
hours: state.hours ?? 0,
|
|
minutes: state.minutes ?? 0)
|
|
.inSeconds,
|
|
),
|
|
);
|
|
},
|
|
backgroundColor: ColorsManager.primaryColor,
|
|
child: const Text('Save'),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
List<Widget> _buildCountDownAngInchingView(
|
|
BuildContext context, WaterHeaterDeviceStatusLoaded state) {
|
|
final isCountDown =
|
|
state.scheduleMode?.name == ScheduleModes.countdown.name;
|
|
return [
|
|
Text(
|
|
isCountDown ? 'Countdown:' : 'Inching:',
|
|
style: context.textTheme.bodySmall!.copyWith(
|
|
fontSize: 13,
|
|
color: ColorsManager.grayColor,
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
Visibility(
|
|
visible: !isCountDown,
|
|
child: const Text(
|
|
'Once enabled this feature, each time the device is turned on, it will automatically turn of after a period time as pre-set.'),
|
|
),
|
|
const SizedBox(height: 8),
|
|
_hourMinutesWheel(state, context)
|
|
];
|
|
}
|
|
|
|
Row _hourMinutesWheel(
|
|
WaterHeaterDeviceStatusLoaded state, BuildContext context) {
|
|
final isActive =
|
|
(state.countdownRemaining != null && state.isActive == true);
|
|
return Row(
|
|
mainAxisAlignment: MainAxisAlignment.start,
|
|
children: [
|
|
_buildPickerColumn(context, 'h', state.hours ?? 0, 24, (value) {
|
|
context.read<WaterHeaterBloc>().add(UpdateScheduleEvent(
|
|
scheduleMode: state.scheduleMode ?? ScheduleModes.countdown,
|
|
hours: value,
|
|
minutes: state.minutes ?? 0,
|
|
));
|
|
}, isActive: isActive),
|
|
const SizedBox(width: 10),
|
|
_buildPickerColumn(context, 'm', state.minutes ?? 0, 60, (value) {
|
|
context.read<WaterHeaterBloc>().add(UpdateScheduleEvent(
|
|
scheduleMode: state.scheduleMode ?? ScheduleModes.countdown,
|
|
hours: state.hours ?? 0,
|
|
minutes: value,
|
|
));
|
|
}, isActive: isActive),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildPickerColumn(BuildContext context, String label,
|
|
int initialValue, int itemCount, ValueChanged<int> onSelected,
|
|
{required bool isActive}) {
|
|
return Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Container(
|
|
height: 40,
|
|
width: 80,
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
decoration: BoxDecoration(
|
|
color: ColorsManager.boxColor,
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: ListWheelScrollView.useDelegate(
|
|
key: ValueKey('$label-$initialValue'),
|
|
controller: FixedExtentScrollController(
|
|
initialItem: initialValue,
|
|
),
|
|
itemExtent: 40.0,
|
|
physics: const FixedExtentScrollPhysics(),
|
|
onSelectedItemChanged: onSelected,
|
|
childDelegate: ListWheelChildBuilderDelegate(
|
|
builder: (context, index) {
|
|
return Center(
|
|
child: Text(
|
|
index.toString().padLeft(2, '0'),
|
|
style: TextStyle(
|
|
fontSize: 24,
|
|
color: isActive ? ColorsManager.grayColor : Colors.black,
|
|
),
|
|
),
|
|
);
|
|
},
|
|
childCount: itemCount,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
label,
|
|
style: const TextStyle(
|
|
color: ColorsManager.grayColor,
|
|
fontSize: 18,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|