In my web app the timetable controller looses the ability to 'animateTo' whenever there is a change in the eventlist. The timetable keeps working correctly otherwise (I can swipe through the weeks manually, updated events show correctly, onTap keeps working, etc.). I can even use the timetableController to get information about the currentstate (e.g. currently displayed week). The only thing that seems to stop working is 'AnimateTo'. If I reload the widget through "popAndPushNamed", it works again, until there is a change in a event. Not a 100% sure this is a bug or an issue with my code, but since everything else seems to work correctly I'm posting it here..
import 'package:flutter/material.dart';
import 'package:flutter_timetable_backend_app/models/event.dart';
import 'package:flutter_timetable_backend_app/screens/home/calendar/src/edit_session.dart';
import 'package:flutter_timetable_backend_app/screens/home/calendar/src/week_list.dart';
import 'package:flutter_timetable_backend_app/screens/home/recurring_sessions/src/location_selection.dart';
import 'package:flutter_timetable_backend_app/services/providers.dart';
import 'package:flutter_timetable_backend_app/shared/loading.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:timetable/timetable.dart';
import 'package:time_machine/time_machine.dart';
class Calendar extends StatefulWidget {
@override
_CalendarState createState() => _CalendarState();
}
class _CalendarState extends State<Calendar> {
static TimetableController<BasicEvent> calController;
List<BasicEvent> myList = [];
EventProvider<BasicEvent> myEventProvider;
@override
void initState() {
super.initState();
}
@override
void dispose() {
calController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// create list of sessions that can be processed by Timetable EventProvider
return Consumer(builder: (context, watch, child) {
final boxData = watch(boxDataProvider).data == null ? null : watch(boxDataProvider).data.value;
final userData = watch(userDataProvider).data == null ? null : watch(userDataProvider).data.value;
final sessionEvents = watch(sessionEventsProvider).data == null ? null : watch(sessionEventsProvider).data.value;
if (boxData == null || sessionEvents == null || userData == null) return Container(alignment: Alignment.topCenter, child: Loading());
final DateTime monday = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().add(Duration(days: 1-DateTime.now().weekday)).day, 0, 0);
SessionEvent sessionEvent;
myList = [];
List<int> weekNumCount = [0,0,0,0];
if (sessionEvents != null) {
sessionEvents.forEach((session) {
session.start.compareTo(monday.add(Duration(days: 7))) < 0 ? weekNumCount[0]++ :
session.start.compareTo(monday.add(Duration(days: 14))) < 0 ? weekNumCount[1]++ :
session.start.compareTo(monday.add(Duration(days: 21))) < 0 ? weekNumCount[2]++ : weekNumCount[3]++;
myList.add(
BasicEvent(
id: session.id,
title: '${session.spotsTaken}/${session.spots}',
color: Color(session.color),
start: LocalDate.dateTime(session.start).at(LocalTime(session.start.hour, session.start.minute, 0)),//LocalDateTime.dateTime(session.start),
end: LocalDate.dateTime(session.end).at(LocalTime(session.end.hour, session.end.minute, 0)),//LocalDateTime.dateTime(session.end),
)
);
});
}
myEventProvider = EventProvider.list(myList);
calController = TimetableController(
eventProvider: myEventProvider,
// Optional parameters with their default values:
initialTimeRange: InitialTimeRange.range(
startTime: LocalTime(6, 0, 0),
endTime: LocalTime(23, 0, 0),
),
initialDate: LocalDate.today(),
visibleRange: VisibleRange.week(),
firstDayOfWeek: DayOfWeek.monday,
);
void animateToWeek(int weekNum) {
calController.animateTo(LocalDate.today().addWeeks(weekNum));
}
return Container(
height: MediaQuery.of(context).size.height-150,
margin: EdgeInsets.only(left: 40.0, top: 40.0, bottom: 40.0, right: 40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Calendar',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 40.0,
),
),
Expanded(
child: Row(
children: [
Expanded(
flex: 1,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 40.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 40.0,),
Text('Select location',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 15.0,),
LocationList(),
SizedBox(height: 40.0,),
Text('Select week',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 20.0,),
WeekList(weekNumCount: weekNumCount, animateToWeek: animateToWeek),
SizedBox(height: 30,),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
],
),
],
),
),
),
Container(
width: 500,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 40.0),
child: Timetable<BasicEvent>(
controller: calController,
theme: TimetableThemeData(
totalDateIndicatorHeight: 74,
primaryColor: boxData.highlight,
),
eventBuilder: (event) =>
BasicEventWidget(event,
onTap: () async {
sessionEvent = sessionEvents.firstWhere((item) => item.id == event.id);
EditSession.editSessionKey.currentState.showEventDetails(sessionEvent);
},
),
allDayEventBuilder: (context, event, info) =>
BasicAllDayEventWidget(event, info: info),
),
),
),
Expanded(
flex: 1,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 40.0),
child: Container(
alignment: Alignment.topCenter,
child: EditSession(boxData: boxData, userData: userData, key: EditSession.editSessionKey),
),
),
)
],
),
),
],
),
);
});
}
}
import 'package:flutter_timetable_backend_app/models/event.dart';
import 'package:flutter_timetable_backend_app/services/database.dart';
import 'package:flutter/material.dart';
import 'package:flutter_timetable_backend_app/shared/loading.dart';
import 'package:flutter_timetable_backend_app/services/providers.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:intl/intl.dart';
class WeekList extends StatefulWidget {
final List<int> weekNumCount;
final Function animateToWeek;
WeekList({this.weekNumCount, this.animateToWeek});
@override
_WeekListState createState() => _WeekListState();
}
class _WeekListState extends State<WeekList> {
int weekDisplayed;
List<SessionEvent> sessionsToDelete;
final int weekNum = weekNumber(DateTime.now());
final DateTime monday = DateTime.now().add(Duration(days: 1-DateTime.now().weekday));
@override
void initState() {
super.initState();
weekDisplayed = weekNum;
}
@override
Widget build(BuildContext context) {
return Consumer(
builder: (context, watch, child) {
final userData = watch(userDataProvider).data == null ? null : watch(userDataProvider).data.value;
final recurringSessions = watch(recurringSessionsProvider).data == null ? null : watch(recurringSessionsProvider).data.value;
final sessionEvents = watch(sessionEventsProvider).data == null ? null : watch(sessionEventsProvider).data.value;
if (userData == null || recurringSessions == null || sessionEvents == null) {return Loading();
} else {
return ListView.builder(
itemCount: 4,
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Text(
(weekNum+index).toString(),
style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
),
title: Text('Mon ${monday.add(Duration(days: 7*index)).day} - Sun ${monday.add(Duration(days: (7*index)+6)).day}'),
subtitle: Text('Scheduled sessions: ${widget.weekNumCount[index]}'),
selected: index + weekNum == weekDisplayed,
onTap: () {
setState(() {
weekDisplayed = weekNum + index;
widget.animateToWeek(index);
});
},
trailing: PopupMenuButton(
onSelected: (selectedValue) async {
switch (selectedValue) {
case 99:
await DatabaseService().scheduleFullWeek(userData, recurringSessions, monday.add(Duration(days: 7 * index)));
break;
case 100:
print('total ${sessionEvents.length}');
sessionsToDelete = sessionEvents.where((session) => session.start.day >= monday.add(Duration(days: 7 * index)).day).toList();
print('after first filter ${sessionsToDelete.length}');
sessionsToDelete = sessionsToDelete.where((session) => session.start.day < monday.add(Duration(days: 7 * index + 7)).day).toList();
print('after second filter ${sessionsToDelete.length}');
await DatabaseService().deleteSessionEvents(userData, sessionsToDelete);
break;
default:
sessionsToDelete = sessionEvents.where((session) => session.start.day == monday.add(Duration(days: 7 * index + selectedValue)).day).toList();
await DatabaseService().deleteSessionEvents(userData, sessionsToDelete);
print(sessionsToDelete.length);
break;
}
},
itemBuilder: (BuildContext ctx) => [
PopupMenuItem(child: Text('Schedule full week'), value: 99),
PopupMenuItem(child: Text('Clear all sessions'), value: 100),
PopupMenuItem(child: Text('Clear Monday'), value: 0),
PopupMenuItem(child: Text('Clear Tuesday'), value: 1),
PopupMenuItem(child: Text('Clear Wednesday'), value: 2),
PopupMenuItem(child: Text('Clear Thursday'), value: 3),
PopupMenuItem(child: Text('Clear Friday'), value: 4),
PopupMenuItem(child: Text('Clear Saturday'), value: 5),
PopupMenuItem(child: Text('Clear Sunday'), value: 6),
]
),
),
);
});
}
}
);
}
}
// Calculates number of weeks for a given year as per https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year
int numOfWeeks(int year) {
DateTime dec28 = DateTime(year, 12, 28);
int dayOfDec28 = int.parse(DateFormat("D").format(dec28));
return ((dayOfDec28 - dec28.weekday + 10) / 7).floor();
}
// Calculates week number from a date as per https://en.wikipedia.org/wiki/ISO_week_date#Calculation
int weekNumber(DateTime date) {
int dayOfYear = int.parse(DateFormat("D").format(date));
int woy = ((dayOfYear - date.weekday + 10) / 7).floor();
if (woy < 1) {
woy = numOfWeeks(date.year - 1);
} else if (woy > numOfWeeks(date.year)) {
woy = 1;
}
return woy;
}