简体   繁体   中英

I have one issue from migrating my flutter app to null_safety

I migrated my application to null-safety. I had some errors and was able to fix all but one last one.

This page is a calendar page and the part where the error occurs is when I am building the calendar. I am using the table_calendar plugin.

I added the "?" after defining the type of function for _getEventsFroDay(). I don't know if this is the right way to do this.

  1. The argument type 'List? Function(DateTime)' can't be assigned to the parameter type 'List Function(DateTime)?'.

This is the function:

List<dynamic>? _getEventsForDay(DateTime day) {
    // kEvents is a linkedHashMap
    for (int i = 0; i < eventDoc.length; i++ ) {
      DateTime eventDate = eventDoc[i].eventDate;
      DateTime eventDateUTC = eventDate.toUtc();
      if (day.year == eventDate.year && day.day == eventDate.day && day.month == eventDate.month) {
        List<dynamic> eventList = [];
        eventList.add(eventDoc[i].agencyId);
        eventList.add(eventDoc[i].agentId);
        eventList.add(eventDoc[i].eventDate);
        eventList.add(eventDoc[i].eventDescription);
        eventList.add(eventDoc[i].eventDuration);
        eventList.add(eventDoc[i].eventName);
        eventList.add(eventDoc[i].eventStartTime);
        //print('kEvents: $kEvents');
        return kEvents.putIfAbsent(eventDateUTC, () => eventList);
      }
    }
  }

This is where the error is occuring:
Widget _buildTableCalendar() {
    return TableCalendar(
      eventLoader: _getEventsForDay, <<<< ERROR HERE

Here is the error message after I remove the "?"from List? _getEventsForDay(DateTime day) {. 在此处输入图片说明

Here is the full .dart file:

// Example holidays
final Map<DateTime, List> _holidays = {
  DateTime(2020, 1, 1): ['New Year\'s Day'],
  DateTime(2020, 1, 6): ['Epiphany'],
  DateTime(2020, 2, 14): ['Valentine\'s Day'],
  DateTime(2020, 4, 21): ['Easter Sunday'],
  DateTime(2020, 4, 22): ['Easter Monday'],
};

final kNow = DateTime.now();
final kFirstDay = DateTime(kNow.year, kNow.month - 3, kNow.day);
final kLastDay = DateTime(kNow.year, kNow.month + 3, kNow.day);

final eventsRef = FirebaseFirestore.instance.collection('agency').doc(globals.agencyId).collection('event');
final _db = FirebaseFirestore.instance;
final _firestoreService = FirestoreService();
bool showSpinner = false;
DateTime? _selectedDay;
DateTime _focusedDay = DateTime.now();
LinkedHashMap<DateTime, List<Event>> kEvents = LinkedHashMap<DateTime, List<Event>>();

class AppointmentCalendarScreen extends StatefulWidget {
  AppointmentCalendarScreen({Key? key, this.title}) : super(key: key);

  final String? title;

  @override
  _AppointmentCalendarScreenState createState() => _AppointmentCalendarScreenState();
}

class _AppointmentCalendarScreenState extends State<AppointmentCalendarScreen> with TickerProviderStateMixin {
  late final ValueNotifier<List<Event>> _selectedEvents;
  Map<DateTime, List>? _selectedEventsMap;
  late StreamController<Map<DateTime, List>> _streamController;
  late var eventDoc;

  @override
  void initState() {
    super.initState();

    _streamController = StreamController();
    _selectedDay = _focusedDay;
    _selectedEvents = ValueNotifier(_getEventsForDay(_selectedDay!));
  }

  @override
  void dispose() {
    _selectedEvents.dispose();
    _streamController.close();

    super.dispose();
  }

  List<Event> _getEventsForDay(DateTime day) {
    // kEvents is a linkedHashMap
    for (int i = 0; i < eventDoc.length; i++ ) {
      DateTime eventDate = eventDoc[i].eventDate;
      DateTime eventDateUTC = eventDate.toUtc();
      if (day.year == eventDate.year && day.day == eventDate.day && day.month == eventDate.month) {
        List<Event> eventList = [];
        eventList.add(eventDoc[i].agencyId);
        eventList.add(eventDoc[i].agentId);
        eventList.add(eventDoc[i].eventDate);
        eventList.add(eventDoc[i].eventDescription);
        eventList.add(eventDoc[i].eventDuration);
        eventList.add(eventDoc[i].eventName);
        eventList.add(eventDoc[i].eventStartTime);
        //print('kEvents: $kEvents');
        return (kEvents.putIfAbsent(eventDateUTC, () => eventList))??[];

      }
    }
  }

  void _onDaySelected(DateTime selectedDay, DateTime focusedDay) {
    if (!isSameDay(_selectedDay, selectedDay)) {
      setState(() {
        _selectedDay = selectedDay;
        _focusedDay = focusedDay;
      });

      _selectedEvents.value = _getEventsForDay(selectedDay);
    }
  }

  void _onVisibleDaysChanged(DateTime first, DateTime last,
      CalendarFormat format) {
  }

  void _onCalendarCreated(DateTime first, DateTime last,
      CalendarFormat format) {
  }

  @override
  Widget build(BuildContext context) {
    final eventProvider = Provider.of<EventProvider>(context);
    FirebaseFirestore _db = FirebaseFirestore.instance;

    return Scaffold(
      appBar: AppBar(
        automaticallyImplyLeading: false,
        title: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Image.asset('assets/images/Appbar_logo.png',
                fit: BoxFit.cover, height: 56),
          ],
        ),
      ),
      backgroundColor: Colors.white,
      resizeToAvoidBottomInset: false,
      body: Column(
        mainAxisSize: MainAxisSize.max,
        children: <Widget>[
          StreamBuilder(
            stream: _db.collection('agency').doc(globals.agencyId).collection('event')
              .where('eventDate', isGreaterThanOrEqualTo: kFirstDay)
              .where('eventDate', isLessThanOrEqualTo: kLastDay)
                    .snapshots().map((snapshot) => snapshot.docs
              .map((document) => Event.fromFirestore(document.data()))
              .toList()),
            builder: (context, AsyncSnapshot <List<Event>> eventsSnapShot) {
              if (eventsSnapShot.hasData) {

                return _buildTableCalendar();
              } else {
                return CircularProgressIndicator();
              }
            },
          ),
          const SizedBox(height: 8.0),
          //_buildButtons(),
          ElevatedButton(
            onPressed: () async {
              setState(() {
                showSpinner = true;
              });
              try {
                globals.newAgency = true;

                Navigator.of(context).pushReplacement(MaterialPageRoute(
                    builder: (context) => AddEventScreen()));

                setState(() {
                  showSpinner = false;
                });
              } catch (e) {
                // todo: add better error handling
                print(e);
              }
            },
            child: Text('Add Event'),
          ),
          const SizedBox(height: 8.0),
          Expanded(child: _buildEventList()),
        ],
      ),
    );
  }

  // Simple TableCalendar configuration (using Styles)
  Widget _buildTableCalendar() {
    return TableCalendar(
      firstDay: kFirstDay,
      lastDay: kLastDay,
      focusedDay: _focusedDay,
      selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
      locale: 'en_US',
      eventLoader: (day) {
        return _getEventsForDay(day);
      },
      startingDayOfWeek: StartingDayOfWeek.sunday,
      calendarStyle: CalendarStyle(
        isTodayHighlighted: true,
        selectedDecoration: BoxDecoration(color: Colors.deepOrange[400]),
        todayDecoration: BoxDecoration(color: Colors.deepOrange[200]),
        markerDecoration: BoxDecoration(color: Colors.deepPurpleAccent),
        outsideDaysVisible: false,
      ),
      headerStyle: HeaderStyle(
        formatButtonTextStyle:
        TextStyle().copyWith(color: Colors.white, fontSize: 15.0),
        formatButtonDecoration: BoxDecoration(
          color: Colors.deepOrange[400],
          borderRadius: BorderRadius.circular(16.0),
        ),
      ),
      onDaySelected: (selectedDay, focusedDay) {
        setState(() {
          _selectedDay = selectedDay;
          _focusedDay = focusedDay; // update `_focusedDay` here as well
        });
      },
      onPageChanged: (focusedDay) {
        _focusedDay = focusedDay;
      },
    );
  }

  Widget _buildHolidaysMarker() {
    return Icon(
      Icons.add_box,
      size: 20.0,
      color: Colors.blueGrey[800],
    );
  }

  Widget _buildEventList() {
    final _db = FirebaseFirestore.instance;

    return Container(
      child: StreamBuilder<QuerySnapshot>(
        //stream: FirestoreService().getEventStream(_focusedDay),
        stream: _db.collection('agency').doc(globals.agencyId).collection(
            'event').where('eventDate', isEqualTo: _focusedDay).snapshots(),
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            return Center(
                child: const Text(
                  'Loading...',
                  style: TextStyle(
                      fontSize: 20, fontWeight: FontWeight.bold),
                ));
          } else {
            var doc = snapshot.data!.docs;
            return new ListView.builder(
                itemCount: doc.length,
                itemBuilder: (BuildContext context, int index) {
                  Event _event = Event.fromFirestore(
                      doc[index].data() as Map<String, dynamic>);
                  return ListTile(
                    isThreeLine: true,
                    title: Text(
                      '${_event.eventName ?? 'n/a'}',
                      style: TextStyle(
                          fontWeight: FontWeight.w900,
                          color: Colors.blueAccent),
                    ),
                    subtitle: Text.rich(TextSpan(
                        text:
                        '${DateFormat('EE MM-dd-yyyy').format(_event.eventDate!) ?? 'n/a'}\n'
                        '${DateFormat('h:mm a').format(_event.eventStartTime!) ?? 'n/a'}, '
                        'Duration: ${_event.eventDuration ?? 'n/a'} minutes',
                        children: <TextSpan>[
                          TextSpan(
                            text:
                            '\n${_event.eventDescription ?? 'n/a'}',
                            style: TextStyle(
                                fontWeight: FontWeight.w900,
                                color: Colors.blueGrey),
                          )
                        ])),
                    //trailing: Text('MLS#: ${_event.mlsNumber ?? 'n/a'}'),
                    onTap: () {
                      globals.newTrxn = false;
                      /*
                    Navigator.of(context).push(MaterialPageRoute(
                        builder: (context) =>
                            AddEventScreen(
                                doc[index].data())));

                     */
                    },
                  );
                }
            );
          }
        },

      ),
    );
  }

  Map<DateTime, List>? convertToMap(List<Event> item) {
    Map<DateTime, List>? result;

    for (int i = 0; i < item.length; i++) {
      Event data = item[i];
      //get the date and convert it to a DateTime variable
      //DateTime currentDate = DateFormat('MM-dd-yyyy - kk:mm').format(data.eventDate);
      DateTime currentDate = DateTime(data.eventDate!.year, data.eventDate!.month, data.eventDate!.day, data.eventDate!.hour, data.eventDate!.minute);

      List eventNames = [];
      //add the event name to the the eventNames list for the current date.
      //search for another event with the same date and populate the eventNames List.
      for (int j = 0; j < item.length; j++) {
        //create temp calendarItemData object.
        Event temp = item[j];
        //establish that the temp date is equal to the current date
        if (data.eventDate == temp.eventDate) {
          //add the event name to the event List.
          eventNames.add(temp.eventName);
        } //else continue
      }

      //add the date and the event to the map if the date is not contained in the map
      if (result == null) {
        result = {
          currentDate: eventNames
        };
      } else {
        result[currentDate] = eventNames;
      }
      return result;
    }
  }
}

If your list is Event type then you should return List<Event>? Instead of List<dynamic>? from _getEventsForDay function. Hope this will solve your problem.

Edited:

My bad. I have read the documentation and it says, you can give the value of eventloader either a null or a function which return type should be a non null list.

So, in your case you are returning a List? which means the function return type can be null. That's why you are getting error.

List<Event> _getEventsForDay(DateTime day) {
    // kEvents is a linkedHashMap
    for (int i = 0; i < eventDoc.length; i++ ) {
      DateTime eventDate = eventDoc[i].eventDate;
      DateTime eventDateUTC = eventDate.toUtc();
      if (day.year == eventDate.year && day.day == eventDate.day && day.month == eventDate.month) {
        List<dynamic> eventList = [];
        eventList.add(eventDoc[i].agencyId);
        eventList.add(eventDoc[i].agentId);
        eventList.add(eventDoc[i].eventDate);
        eventList.add(eventDoc[i].eventDescription);
        eventList.add(eventDoc[i].eventDuration);
        eventList.add(eventDoc[i].eventName);
        eventList.add(eventDoc[i].eventStartTime);
        //print('kEvents: $kEvents');
        return kEvents.putIfAbsent(eventDateUTC, () => eventList);
      }
    }
  }

Second problem:

Now this error is telling that kEvents.putIfAbsent(eventDateUTC, () => eventList); may return null. Which is not acceptable because our function will not return any null value now. In this case we can use null check operator like this.

return (kEvents.putIfAbsent(eventDateUTC, () => eventList))??[];

Hope this will solve your problem.

  List<Event> _getEventsForDay(DateTime day) {
    // kEvents is a linkedHashMap
    for (int i = 0; i < eventDoc.length; i++ ) {
      DateTime eventDate = eventDoc[i].eventDate;
      DateTime eventDateUTC = eventDate.toUtc();
      if (day.year == eventDate.year && day.day == eventDate.day && day.month == eventDate.month) {
        List<dynamic> eventList = [];
        eventList.add(eventDoc[i].agencyId);
        eventList.add(eventDoc[i].agentId);
        eventList.add(eventDoc[i].eventDate);
        eventList.add(eventDoc[i].eventDescription);
        eventList.add(eventDoc[i].eventDuration);
        eventList.add(eventDoc[i].eventName);
        eventList.add(eventDoc[i].eventStartTime);
        //print('kEvents: $kEvents');
        return kEvents.putIfAbsent(eventDateUTC, () => eventList);
      }
    }
  }

Since your for has an if clause inside of it, and the eventDoc.length can be empty, there is a possibility of your function never reaching the return statement:

return kEvents.putIfAbsent(eventDateUTC, () => eventList);

So what the IDE is telling is that you need to add a return to the end of the function, so it can return null, if eventDoc.length < 1 or the if clause is never fulfilled.

To solve your problem add:

return [];

After your for loop, at the end of the function:

List<Event> _getEventsForDay(DateTime day) {
    // kEvents is a linkedHashMap
    for (int i = 0; i < eventDoc.length; i++ ) {
      DateTime eventDate = eventDoc[i].eventDate;
      DateTime eventDateUTC = eventDate.toUtc();
      if (day.year == eventDate.year && day.day == eventDate.day && day.month == eventDate.month) {
        List<dynamic> eventList = [];
        eventList.add(eventDoc[i].agencyId);
        eventList.add(eventDoc[i].agentId);
        eventList.add(eventDoc[i].eventDate);
        eventList.add(eventDoc[i].eventDescription);
        eventList.add(eventDoc[i].eventDuration);
        eventList.add(eventDoc[i].eventName);
        eventList.add(eventDoc[i].eventStartTime);
        //print('kEvents: $kEvents');
        return kEvents.putIfAbsent(eventDateUTC, () => eventList);
      }
    }

    return [];
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM