I'm trying to allow users to choose their working hours for a week for that I've done a List
of days of the week and used a ListView.builder
to display all days as shown below.
Now I would like to allow users to change start hour and end hour for each day.
For that I call a TimePicker
on click but when I change a start hour, all start hours are changed.
My question is, is that a good idea to use a ListView
to generate the days and if yes how to modiify hours one by one for each day without modify the others at the same time.
Here is the code:
Utils
static String displayCorrectTimeOfDay(int hour, int minute) {
final hours = hour.toString().padLeft(2, '0');
final minutes = minute.toString().padLeft(2, '0');
return "${hours}h$minutes";
}
Text
const String monday = "Mon.";
const String tuesday = "Tue.";
const String wednesday = "Wed";
const String thursday = "Thu.";
const String friday = "Fri.";
const String saturday = "Sat.";
const String sunday = "Sun.";
WeeklyScheduleScreen
class WeeklyScheduleScreen extends StatefulWidget {
const WeeklyScheduleScreen({Key? key}) : super(key: key);
@override
State<WeeklyScheduleScreen> createState() => _WeeklyScheduleScreenState();
}
class _WeeklyScheduleScreenState extends State<WeeklyScheduleScreen> {
TimeOfDay from = const TimeOfDay(hour: 7, minute: 00);
TimeOfDay to = const TimeOfDay(hour: 23, minute: 00);
List<String> week = [monday, tuesday, wednesday, thursday, friday, saturday, sunday];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: const CloseButton(
color: white,
),
title: const Text(
myWeek,
style: TextStyle(
color: white,
),
),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 15,),
buildSubTitle(),
const SizedBox(height: 25,),
buildWeek(),
//buildFrom(),
],
),
),
);
}
Widget buildSubTitle() => const Text(
myWeekSubTitle,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
);
Widget buildWeek() => ListView.builder(
itemCount: week.length,
itemBuilder: (_, i) => buildSelectHour(week[i]),
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
);
Widget buildSelectHour(String day) => Row(
children: [
Text(
day,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Expanded(
flex: 3,
child: buildDropDownField(
text: Utils.displayCorrectTimeOfDay(from.hour, from.minute),
onClicked: () => pickFromTime(),
),
),
Expanded(
flex: 3,
child: buildDropDownField(
text: Utils.displayCorrectTimeOfDay(to.hour, to.minute),
onClicked: () => pickToTime(),
),
),
Expanded(
flex: 1,
child: IconButton(
onPressed: () { print( "Done clicked"); },
icon: const Icon(
Icons.check_circle,
color: phoneButtonColor,
),
),
),
Expanded(
flex: 1,
child: IconButton(
onPressed: () { print( "Cancel clicked"); },
icon: const Icon(
Icons.cancel,
color: red,
),
),
),
],
);
Widget buildDropDownField({required String text, required VoidCallback onClicked}) =>
ListTile(
title: Text(text),
trailing: const Icon(Icons.arrow_drop_down),
onTap: onClicked,
);
Future pickFromTime() async {
TimeOfDay? timePicked = await showTimePicker(
context: context,
initialTime: from,
);
if(timePicked == null) return;
setState(() => from = timePicked);
}
Future pickToTime() async {
TimeOfDay? timePicked = await showTimePicker(
context: context,
initialTime: to,
);
if(timePicked == null) return;
setState(() => to = timePicked);
}
}
Thanks in advance
CodePudding user response:
You just created one TimeOfDay that you applied to all items.
Just create a List with all TimeOfDay's so you can easily access them through the builders index, for example:
...
List<TimeOfDay> froms = [const TimeOfDay(hour: 7, minute: 00),...];
<TimeOfDay> tos = [const TimeOfDay(hour: 23, minute: 00),...];
...
Widget buildSelectHour(String day, int index) => Row(
children: [
Text(
day,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Expanded(
flex: 3,
child: buildDropDownField(
text: Utils.displayCorrectTimeOfDay(froms[index].hour, froms[index].minute),
onClicked: () => pickFromTime(),
),
),
Expanded(
flex: 3,
child: buildDropDownField(
text: Utils.displayCorrectTimeOfDay(tos[index].hour, tos[index].minute),
onClicked: () => pickToTime(),
),
),
Expanded(
flex: 1,
child: IconButton(
onPressed: () { print( "Done clicked"); },
icon: const Icon(
Icons.check_circle,
color: phoneButtonColor,
),
),
),
Expanded(
flex: 1,
child: IconButton(
onPressed: () { print( "Cancel clicked"); },
icon: const Icon(
Icons.cancel,
color: red,
),
),
),
],
);
Future pickFromTime(int index) async {
TimeOfDay? timePicked = await showTimePicker(
context: context,
initialTime: from,
);
if(timePicked == null) return;
setState(() => froms[index] = timePicked);
}
Future pickToTime(int index) async {
TimeOfDay? timePicked = await showTimePicker(
context: context,
initialTime: to,
);
if(timePicked == null) return;
setState(() => tos[index] = timePicked);
}
CodePudding user response:
try to make WeekDays model class
void main() {
List<WeekDays> week = [
WeekDays(days: "Mon."),
WeekDays(days: "Tue."),
WeekDays(days: "Wed."),
WeekDays(days: "Thu."),
WeekDays(days: "Fri."),
WeekDays(days: "Sat."),
WeekDays(days: "Sun."),
];
week.forEach((day) {
print("${day.days} ${day.startHour} ${day.endHour}");
});
}
class WeekDays {
final String days;
double startHour;
double endHour;
WeekDays({
required this.days,
this.startHour = 7.0,
this.endHour = 24.0,
});
}