i am working on a school timetable for my undergraduate project work. in My project i am using flutter and my app runs on both desktop and web. Anytime i am performing some looping and conditions, my application will pause (Freez) until the action is done. This cuase all other activities to stop such as circular progress and any other thing.
Note that i am using Riverpod for state management
Bellow is an example function that pause my app whhen it is called.
void generateWithCombineClasses(WidgetRef ref)async {
// CustomDialogs.loading(message: 'Generating table items for remaining Items');
var config = ref.watch(configProvider).currentConfig;
var vtps = ref
.watch(venueTimePairProvider)
.where((element) => element.isAssigned == false)
.toList();
var cclps = state.where((element) => element.isAssigned == false).toList();
var tableItems = ref.watch(generatedTableProvider).items.toList();
cclps.shuffle();
List<VenueTimePairModel> usedVtps = [];
for (var vtp in vtps) {
if (!vtp.isAssigned && !usedVtps.contains(vtp)) {
//pick all cclps that have not been assigned and a lecturer or class is not found in the existing table items
var cclpsToAssign = cclps
.where((element) =>
!element.isAssigned &&
!lecturerOrClassIsInTableItem(tableItems, element, vtp) &&
isNotClassLiberalTime(vtp, element, config) &&
isNotLecturerFreeDay(vtp, element) &&
isEveningVenue(vtp, element, config) &&
isEqual(element.venueType, vtp.venueType))
.toList();
if (cclpsToAssign.isNotEmpty) {
//group cclps with same lecturer, same course, same class level and same study mode
var groupByCriteria = groupBy(
cclpsToAssign,
(ClassCourseLecturerPairModel e) =>
'${e.courseId}-${e.level}-${e.studyMode}-${e.lecturerId}');
//if no data meets the criteria we pick any cclp
if (groupByCriteria.isEmpty) {
//just pick any cclp that can fit the vtp capacity
var cclp = cclpsToAssign.any(
(element) => element.classSize <= (vtp.venueCapacity + 35))
? cclpsToAssign.firstWhere(
(element) => element.classSize <= (vtp.venueCapacity + 35))
: cclpsToAssign.firstOrNull;
if (cclp != null) {
var tableItem = makeTableItem(
vtp: vtp,
cclps: [cclp],
config: config,
);
tableItems.add(tableItem);
usedVtps.add(vtp);
cclps = cclps
.map((element) => element.id == cclp.id
? cclp.copyWith(isAssigned: true)
: element)
.toList();
}
} else {
//pick any of the item that has the most number of cclps
var valuesToList = groupByCriteria.values.toList();
if (valuesToList.isNotEmpty) {
var cclpWithHighestCount = groupByCriteria.values
.toList()
.reduce((value, element) =>
value.length > element.length ? value : element)
.toList();
//here we check if 4 cclps can be combined to fit the vtp capacity
//else check if 3 cclps can be combined to fit the vtp capacity
//else check if 2 cclps can be combined to fit the vtp capacity
//else check if 1 cclp can fit the vtp capacity
//else we pick the cclp that can fit the vtp capacity
if (cclpWithHighestCount.length > 3) {
//we check if 4 cclps can be combined to fit the vtp capacity
var totalCapacity = cclpWithHighestCount.sublist(0, 4).fold(
0,
(previousValue, element) =>
previousValue + element.classSize);
if (totalCapacity <= (vtp.venueCapacity + 35)) {
var tableItem = makeTableItem(
vtp: vtp,
cclps: cclpWithHighestCount.sublist(0, 4),
config: config,
);
tableItems.add(tableItem);
usedVtps.add(vtp);
cclps = cclps
.map((element) =>
cclpWithHighestCount.sublist(0, 4).contains(element)
? element.copyWith(isAssigned: true)
: element)
.toList();
} else if (cclpWithHighestCount.sublist(0, 3).fold(
0,
(previousValue, element) =>
previousValue + element.classSize) <=
(vtp.venueCapacity + 35)) {
//we check if 3 cclps can be combined to fit the vtp capacity
var tableItem = makeTableItem(
vtp: vtp,
cclps: cclpWithHighestCount.sublist(0, 3),
config: config,
);
tableItems.add(tableItem);
usedVtps.add(vtp);
cclps = cclps
.map((element) =>
cclpWithHighestCount.sublist(0, 3).contains(element)
? element.copyWith(isAssigned: true)
: element)
.toList();
} else if (cclpWithHighestCount.sublist(0, 2).fold(
0,
(previousValue, element) =>
previousValue + element.classSize) <=
(vtp.venueCapacity + 35)) {
//we check if 2 cclps can be combined to fit the vtp capacity
var tableItem = makeTableItem(
vtp: vtp,
cclps: cclpWithHighestCount.sublist(0, 2),
config: config,
);
tableItems.add(tableItem);
usedVtps.add(vtp);
cclps = cclps
.map((element) =>
cclpWithHighestCount.sublist(0, 2).contains(element)
? element.copyWith(isAssigned: true)
: element)
.toList();
} else if (cclpWithHighestCount.first.classSize <=
(vtp.venueCapacity + 35)) {
//we check if 1 cclp can fit the vtp capacity
var tableItem = makeTableItem(
vtp: vtp,
cclps: cclpWithHighestCount.sublist(0, 1),
config: config,
);
tableItems.add(tableItem);
usedVtps.add(vtp);
cclps = cclps
.map((element) =>
cclpWithHighestCount.sublist(0, 1).contains(element)
? element.copyWith(isAssigned: true)
: element)
.toList();
} else {
//just just pick the smallest cclp and assign it to the vtp
var tableItem = makeTableItem(
vtp: vtp,
cclps: [cclpWithHighestCount.first],
config: config,
);
tableItems.add(tableItem);
usedVtps.add(vtp);
cclps = cclps
.map((element) =>
cclpWithHighestCount.sublist(0, 1).contains(element)
? element.copyWith(isAssigned: true)
: element)
.toList();
}
} else if (cclpWithHighestCount.length > 2) {
//we check if 3 cclps can be combined to fit the vtp capacity
var totalCapacity = cclpWithHighestCount.sublist(0, 3).fold(
0,
(previousValue, element) =>
previousValue + element.classSize);
if (totalCapacity <= (vtp.venueCapacity + 35)) {
var tableItem = makeTableItem(
vtp: vtp,
cclps: cclpWithHighestCount.sublist(0, 3),
config: config,
);
tableItems.add(tableItem);
usedVtps.add(vtp);
cclps = cclps
.map((element) =>
cclpWithHighestCount.sublist(0, 3).contains(element)
? element.copyWith(isAssigned: true)
: element)
.toList();
} else if (cclpWithHighestCount.sublist(0, 2).fold(
0,
(previousValue, element) =>
previousValue + element.classSize) <=
(vtp.venueCapacity + 35)) {
//we check if 2 cclps can be combined to fit the vtp capacity
var tableItem = makeTableItem(
vtp: vtp,
cclps: cclpWithHighestCount.sublist(0, 2),
config: config,
);
tableItems.add(tableItem);
usedVtps.add(vtp);
cclps = cclps
.map((element) =>
cclpWithHighestCount.sublist(0, 2).contains(element)
? element.copyWith(isAssigned: true)
: element)
.toList();
} else if (cclpWithHighestCount.first.classSize <=
(vtp.venueCapacity + 35)) {
//we check if 1 cclp can fit the vtp capacity
var tableItem = makeTableItem(
vtp: vtp,
cclps: cclpWithHighestCount.sublist(0, 1),
config: config,
);
tableItems.add(tableItem);
usedVtps.add(vtp);
cclps = cclps
.map((element) =>
cclpWithHighestCount.sublist(0, 1).contains(element)
? element.copyWith(isAssigned: true)
: element)
.toList();
} else {
//just just pick the smallest cclp and assign it to the vtp
var tableItem = makeTableItem(
vtp: vtp,
cclps: [cclpWithHighestCount.first],
config: config,
);
tableItems.add(tableItem);
usedVtps.add(vtp);
cclps = cclps
.map((element) =>
cclpWithHighestCount.sublist(0, 1).contains(element)
? element.copyWith(isAssigned: true)
: element)
.toList();
}
} else if (cclpWithHighestCount.length > 1) {
//we check if 2 cclps can be combined to fit the vtp capacity
var totalCapacity = cclpWithHighestCount.sublist(0, 2).fold(
0,
(previousValue, element) =>
previousValue + element.classSize);
if (totalCapacity <= (vtp.venueCapacity + 35)) {
var tableItem = makeTableItem(
vtp: vtp,
cclps: cclpWithHighestCount.sublist(0, 2),
config: config,
);
tableItems.add(tableItem);
usedVtps.add(vtp);
cclps = cclps
.map((element) =>
cclpWithHighestCount.sublist(0, 2).contains(element)
? element.copyWith(isAssigned: true)
: element)
.toList();
} else if (cclpWithHighestCount.first.classSize <=
(vtp.venueCapacity + 35)) {
//we check if 1 cclp can fit the vtp capacity
var tableItem = makeTableItem(
vtp: vtp,
cclps: cclpWithHighestCount.sublist(0, 1),
config: config,
);
tableItems.add(tableItem);
usedVtps.add(vtp);
cclps = cclps
.map((element) =>
cclpWithHighestCount.sublist(0, 1).contains(element)
? element.copyWith(isAssigned: true)
: element)
.toList();
} else {
//just just pick the smallest cclp and assign it to the vtp
var tableItem = makeTableItem(
vtp: vtp,
cclps: [cclpWithHighestCount.first],
config: config,
);
tableItems.add(tableItem);
usedVtps.add(vtp);
cclps = cclps
.map((element) =>
cclpWithHighestCount.sublist(0, 1).contains(element)
? element.copyWith(isAssigned: true)
: element)
.toList();
}
} else {
//we check if 1 cclp can fit the vtp capacity
if (cclpWithHighestCount.first.classSize <=
(vtp.venueCapacity + 35)) {
var tableItem = makeTableItem(
vtp: vtp,
cclps: cclpWithHighestCount.sublist(0, 1),
config: config,
);
tableItems.add(tableItem);
usedVtps.add(vtp);
cclps = cclps
.map((element) =>
cclpWithHighestCount.sublist(0, 1).contains(element)
? element.copyWith(isAssigned: true)
: element)
.toList();
} else {
//just just pick the smallest cclp and assign it to the vtp
var tableItem = makeTableItem(
vtp: vtp,
cclps: [cclpWithHighestCount.first],
config: config,
);
tableItems.add(tableItem);
usedVtps.add(vtp);
cclps = cclps
.map((element) =>
cclpWithHighestCount.sublist(0, 1).contains(element)
? element.copyWith(isAssigned: true)
: element)
.toList();
}
}
}
}
}
}
//await Future.delayed(Duration(seconds: 1));
}
ref.read(venueTimePairProvider.notifier).makeVTPAssigned(usedVtps);
ref.read(generatedTableProvider.notifier).setTableItems(tableItems);
//get unassigned cclps and vtps
var unassignedCCLPs =
cclps.where((element) => !element.isAssigned).toList();
updateState(unassignedCCLPs);
// for (var cclp in unassignedCCLPs) {
// print('........................................');
// print('${cclp.courseCode}: ${cclp.courseTitle}');
// print('CS: ${cclp.studyMode}: ClS: ${cclp.studyMode}');
// print(cclp.venueType);
// print('........................................');
// }
print('Number of unassigned cclps: ${unassignedCCLPs.length}');
// var unassignedVTPs = ref
var unassignedVTPs = ref
.watch(venueTimePairProvider)
.where((element) => !element.isAssigned)
.toList();
print('Number of unassigned vtps: ${unassignedVTPs.length}');
//count all classes in table items
var allClasses =
tableItems.map((e) => e.classIds).expand((element) => element).toList();
print('Number of table items: ${allClasses.length}');
// ref.read(isLoadingProvider.notifier).state = (false, '');
//CustomDialogs.dismiss();
}
I tried to use Isolation(Compute) but was not able to figure out how to use it with this fuction.
3