Search code examples
flutterdartpass-by-referenceprovider

Update items shown in two different views with their own controllers in flutter


I'm new to flutter, and I'm trying to build an application to organize a personal schedule. I have two views, one for the confirmed events and the other for the non-confirmed ones. Using calendar_view, each of them has its controller, which I extended with my own provider:

class PrivateProvider extends EventController {
  static final PrivateProvider _instance = PrivateProvider._internal();

  factory PrivateProvider() {
    return _instance;
  }
  PrivateProvider._internal() : super();
  
  addEvents(List<Event> events){
    super.addAll(events);
    notifyListeners();
  }
  addEvent(Event event){
    super.add(event);
    notifyListeners();
  }
}

this is the eventview widget:

@override
  Widget build(BuildContext context) {
    var eventsProvider = widget.private ? PrivateProvider() : SharedProvider();

    return Scaffold(
      body: WeekView(
        controller: eventsProvider,
        onEventTap: (events, date) => showCustomDialog(
            context,
            EventDetail(
                initialEvent: events.whereType<Event>().toList().first,
                date: null,
                confirmed: widget.private)),
      ),
);

this is the filtering and initializing logic for each controller:

 void addEvents(List<Event> events) {

    List<Event> sharedEvents = events
        .where((ev) => ev.confirmed == false)
        .toList();
    List<Event> privateEvents = events
        .where((ev) => ev.confirmed == true)
        .toList();

    PrivateProvider().addEvents(privateEvents);
    SharedProvider().addEvents(sharedEvents);
  }

Now, as from the above code, the only difference between the two list of Events is the boolean variable "confimed" the user can change, then the event should move from one view to the other.

What I'm doing right now is removing the event from one controller and adding it to the other, but I was wandering if there was a way to have all of this done automatically. Like, all I really need is one single list of the user's events and then show them in two different views based on the current "confirmed" status. The first idea it comes to mind is to pass the elements by reference and not by value.

This would also be really useful for when an event updates (I'm planning to have real time updates, so I should also update the event passed in EventDetail), such that I don't have to search it in one of the two controllers but that would be automatic.

Is there a way I can separate the business logic from the view logic? Maybe with a central event provider?

I am willing to eventually download and modify the calendar_view controller logic


Solution

  • calendar_view's EventController has a Filter function that allows to filter the showed items. This makes it possible to handle all the events in one single controller, which makes updates much faster, and allows to handle the viewing login without interfering with the business logic. My was a very particular case, but if can be of any help:

    myUpdateFilter() {
      super.updateFilter(newFilter: (date, events) => myEventFilter(date, events));
    }
    
    List<Event> myEventFilter<T extends Object?>(
      DateTime date, List<CalendarEventData<T>> events) {
      return events
        .whereType<Event>()
        .where(
            (event) => event.occursOnDate(date) && event.confirmed() == private)
        .toList();
    }