TheAlphamerc / filterlist

filterList is a flutter package which provide utility to search/filter data from provided dynamic list.
https://pub.dev/packages/filter_list
BSD 2-Clause "Simplified" License
207 stars 66 forks source link

Not Updating UI After Item Removal / Item can't be selected #51

Closed Giacomo-Cattani closed 2 months ago

Giacomo-Cattani commented 2 months ago

Describe the Bug

I have a homepage that displays a calendar and the events for the selected day. After I click on the filter icon, it displays a ModalBottomSheet. When I click on the filter, this ModalBottomSheet appears and opens using the showModalBottomSheet method. This builds a new component where the FilterDialog and the rest of the page are constructed.

When tapping on a read-only text field, it triggers the function to build the FilterDialog. Everything seems to work fine initially, but after I select one or more items, close the ModalBottomSheet, and then reopen it, the problem appears.

You can understand the issue better by watching this video:

https://github.com/TheAlphamerc/filterlist/assets/151133021/c77acc74-a0fa-44ab-b4d7-e0ba1bba7881

I tried to fix the problem using the validateRemoveItem, and it does what it's supposed to do by removing the element from the list. However, the issue is that it doesn't update the UI immediately. The UI only refreshes if I click on another item. Is there a way to reload the UI or another method to resolve this problem?


This is the code of the pages:

HomePage

import 'package:flutter/material.dart';
import 'package:hyfix/FilterBox.dart';
import 'package:hyfix/WeeksDay.dart';
import 'package:hyfix/main.dart';
import 'package:hyfix/models/Reports.dart';
import 'package:hyfix/services/Service.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'TableBasic.dart';
import 'ContainerEvents.dart';
import 'InsertActivity.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:provider/provider.dart';
import 'Login.dart' as globals;

class JobList with ChangeNotifier {
  List<Reports> lista = <Reports>[];
  List<Reports> listaEventi = <Reports>[];
  DateTime focusedDay = DateTime.now();

  void addElement(Reports report) {
    lista.add(report);
    notifyListeners();
  }

  void updateLista() {
    listaEventi.clear();
    notifyListeners();
  }

  void eventiGiorno(DateTime data) {
    listaEventi.clear();
    for (var element in lista) {
      if (DateUtils.isSameDay(element.reportDate, data)) {
        listaEventi.add(element);
      }
    }
    notifyListeners();
  }

  void addFocused(DateTime data) {
    focusedDay = data;
    notifyListeners();
  }
}

class DataFetch with ChangeNotifier {
  dynamic first;
  dynamic last;
  String type = 'R';
  List<Cliente> customer = [];
  List<Luogo> location = [];
  List<Progetto> project = [];
  List<Attivita> projectTask = [];
  List<TipoAttivita> taskType = [];
  List<Utente> user = [];

  void initData() {
    DateTime focusedDay = DateTime.now();

    List<List<DateTime>> weeks = getWeeksOfMonth(focusedDay);

    first = weeks.first.first;
    last = weeks.last.last;
    type = 'R';
    customer = [];
    location = [];
    project = [];
    projectTask = [];
    taskType = [];
    user = [];
  }
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

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

class _MyAppState extends State<MyApp> {
  DateTime _data = DateTime.now();
  bool visible = true;
  CalendarFormat _calendarFormat = CalendarFormat.month;
  bool loading = true;

  int i = 0;

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

    DateTime focusedDay = DateTime.now();

    List<List<DateTime>> weeks = getWeeksOfMonth(focusedDay);

    fetchRep(first: weeks.first.first, last: weeks.last.last, type: 'R');
  }

  void fetchRep(
      {required dynamic first,
      required dynamic last,
      required String type,
      List? customer,
      List? location,
      List? project,
      List? projectTask,
      List? taskType,
      List? user}) {
    var jobList = context.read<JobList>();
    setState(() {
      loading = true;
    });
    Service()
        .getReports(
            globals.sesid,
            first,
            last,
            type,
            customer ?? '',
            location ?? '',
            project ?? '',
            projectTask ?? '',
            taskType ?? '',
            user ?? '')
        .then((report) {
      if (report == false) {
        logout();
      } else {
        setState(() {
          loading = false;
        });
        jobList.lista = <Reports>[];
        for (var element in report) {
          Reports reports = Reports.fromJson(element);
          jobList.lista.add(reports);
        }
        setState(() {
          jobList.lista = jobList.lista;
          if (jobList.listaEventi.isEmpty) {
            jobList.eventiGiorno(_data);
          }
        });
      }
    });
  }

  void logout() {
    Service().logout(globals.sesid).then(
      (response) async {
        JobList jobList = context.read<JobList>();
        jobList.lista = <Reports>[];

        var prefs = await SharedPreferences.getInstance();
        prefs.remove('username');
        prefs.remove('sesid');

        Navigator.push(
          context,
          MaterialPageRoute(builder: (context) => const Accesso()),
        );
      },
    );
  }

  void aggiornaData(DateTime data) {
    var jobList = context.read<JobList>();
    if (_data == data) {
      visible = !visible;
    } else {
      visible = true;
    }
    setState(() {
      _data = data;
    });
    jobList.eventiGiorno(_data);
  }

  void updateFormat(CalendarFormat format) {
    setState(() {
      _calendarFormat = format;
    });
  }

  void update() {
    var updList = context.read<JobList>();

    updList.updateLista();
  }

  Future<void> _handleRefresh() async {
    final dataFetch = context.read<DataFetch>();
    final jobList = context.read<JobList>();

    // Update the list of items and refresh the UI

    DateTime focusedDay = DateTime.now();

    List<List<DateTime>> weeks = getWeeksOfMonth(focusedDay);

    dataFetch.initData();
    jobList.updateLista();

    fetchRep(first: weeks.first.first, last: weeks.last.last, type: 'R');
  }

  @override
  Widget build(BuildContext context) {
    var themeProvider = context.watch<ThemeProvider>();
    var jobList = context.watch<JobList>();

    double screenWidth = MediaQuery.of(context).size.width;
    double screenHeight = MediaQuery.of(context).size.height;

    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => JobList()),
        ChangeNotifierProvider(create: (context) => DataFetch()),
      ],
      child: Scaffold(
        appBar: AppBar(
          scrolledUnderElevation: 0,
          toolbarHeight: screenHeight / 100 * 6,
          leading: IconButton(
            onPressed: () {
              themeProvider
                  .toggleTheme(themeProvider.themeMode == ThemeMode.light);
            },
            icon: Icon(
              themeProvider.themeMode == ThemeMode.light
                  ? Icons.dark_mode
                  : Icons.light_mode,
              color: Theme.of(context).colorScheme.onSurface,
            ),
          ),
          actions: [
            PopScope(
              canPop: false,
              child: IconButton(
                onPressed: () {
                  logout();
                },
                icon: Icon(
                  Icons.logout,
                  color: Theme.of(context).colorScheme.errorContainer,
                ),
              ),
            ),
          ],
          title: Center(
            child: Text('LE TUE ATTIVITÀ',
                style: TextStyle(
                  color: Theme.of(context).colorScheme.primaryContainer,
                  fontWeight: FontWeight.bold,
                  fontSize: screenWidth / 100 * 7,
                )),
          ),
        ),
        body: RefreshIndicator(
          onRefresh: _handleRefresh,
          child: CustomScrollView(
            slivers: [
              SliverFillRemaining(
                child: Container(
                  padding: const EdgeInsets.all(15),
                  child: Column(
                    children: [
                      TableBasic(
                        lista: jobList.lista,
                        onDaySelected: aggiornaData,
                        calendarFormat: _calendarFormat,
                        updateFormat: updateFormat,
                        fetchCalendar: fetchRep,
                        update: jobList.addFocused,
                        visible: visible,
                      ),
                      Expanded(
                        child: ContainerEvents(
                          loading: loading,
                          selezionato: _data,
                          visible: visible,
                          lista: jobList.listaEventi,
                          fetchRep: fetchRep,
                          dayReload: jobList.updateLista,
                          data: jobList.focusedDay,
                        ),
                      ),
                      Align(
                        alignment: Alignment.bottomRight,
                        child: Container(
                          margin: const EdgeInsets.fromLTRB(0, 15, 10, 15),
                          child: FloatingActionButton(
                            backgroundColor:
                                Theme.of(context).colorScheme.primaryContainer,
                            onPressed: () {
                              Navigator.of(context)
                                  .push(_createRoute(fetchRep, _data, update));
                            },
                            child: const Icon(Icons.add_rounded),
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Route _createRoute(fetchRep, data, update) {
  return PageRouteBuilder(
    transitionDuration: const Duration(milliseconds: 750),
    pageBuilder: (context, animation, secondaryAnimation) => InsertActivity(
        fetchCalendar: fetchRep, update: update, dataAttuale: data),
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      const begin = Offset(0.0, 1.0);
      const end = Offset.zero;
      const curve = Curves.fastOutSlowIn;

      var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));

      return SlideTransition(
        position: animation.drive(tween),
        child: child,
      );
    },
  );
}

ContainerEvents

import 'package:flutter/material.dart';
import 'package:hyfix/Events.dart';
import 'package:hyfix/models/Reports.dart';
import 'package:loading_animation_widget/loading_animation_widget.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:intl/src/intl/date_format.dart';
import 'package:hyfix/FilterBox.dart';

class ContainerEvents extends StatefulWidget {
  const ContainerEvents(
      {required this.selezionato,
      required this.lista,
      required this.data,
      required this.loading,
      required this.fetchRep,
      required this.dayReload,
      super.key,
      required this.visible});
  final DateTime selezionato;
  final bool visible;
  final List<Reports> lista;
  final bool loading;
  final Function fetchRep;
  final DateTime data;
  final Function dayReload;

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

class _ContainerEvents extends State<ContainerEvents> {
  bool controllo() {
    bool check = false;
    for (Reports ele in widget.lista) {
      if (DateUtils.isSameDay(widget.selezionato, ele.reportDate)) {
        check = true;
      }
    }

    return check;
  }

  @override
  void initState() {
    super.initState();
    initializeDateFormatting('it_IT', null);
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(top: 15),
      child: AnimatedVisibility(
          enter: fadeIn(),
          exit: fadeOut(),
          child: Container(
              width: MediaQuery.of(context).size.width,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(10),
                color: Theme.of(context).colorScheme.tertiaryContainer,
              ),
              child: widget.loading
                  ? Center(
                      child: LoadingAnimationWidget.staggeredDotsWave(
                        color:
                            Theme.of(context).colorScheme.onTertiaryContainer,
                        size: 80,
                      ),
                    )
                  : Column(
                      children: [
                        const SizedBox(
                          height: 10,
                        ),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                          children: [
                            Text(
                                "${DateFormat.EEEE('it_IT').format(widget.selezionato)}, ${DateFormat.MMMd('it_IT').format(widget.selezionato)}, ${DateFormat.y('it_IT').format(widget.selezionato)}",
                                style: TextStyle(
                                    color: Colors.white,
                                    fontSize:
                                        MediaQuery.of(context).size.height /
                                            100 *
                                            2.5,
                                    fontWeight: FontWeight.bold)),
                            ElevatedButton(
                                style: ElevatedButton.styleFrom(
                                  backgroundColor: Theme.of(context)
                                      .colorScheme
                                      .inverseSurface,
                                ),
                                onPressed: () {
                                  showModalBottomSheet(
                                    context: context,
                                    isScrollControlled: true,
                                    builder: (context) => Filterbox(
                                        fetchRep: widget.fetchRep,
                                        data: widget.data,
                                        aggiornaData: widget.dayReload),
                                  );
                                },
                                child: Icon(
                                  Icons.filter_alt,
                                  color: Theme.of(context).colorScheme.surface,
                                ))
                          ],
                        ),
                        const SizedBox(
                          height: 10,
                        ),
                        Expanded(
                            child: Padding(
                          padding: const EdgeInsets.only(bottom: 5),
                          child: Events(
                              data: widget.selezionato, lista: widget.lista),
                        )),
                      ],
                    ))),
    );
  }
}

FilterBox

import 'package:filter_list/filter_list.dart';
import 'package:flutter/material.dart';
import 'package:hyfix/Home.dart';
import 'package:hyfix/WeeksDay.dart';
import 'package:provider/provider.dart';
import 'dart:convert';
import 'package:hyfix/services/Service.dart';
import 'Login.dart' as globals;

class Cliente {
  dynamic customer_id;
  dynamic customer_code;
  dynamic customer_companyname;
  String label = "";

  Cliente(this.customer_id, this.customer_code, this.customer_companyname) {
    customer_id = customer_id;
    customer_code = customer_code;
    customer_companyname = customer_companyname;
    label = "$customer_code - $customer_companyname";
  }
  @override
  String toString() {
    return "$customer_code - $customer_companyname";
  }
}

class Luogo {
  dynamic location_id;
  dynamic location_code;
  dynamic location_city;
  String label = "";

  Luogo(this.location_id, this.location_code, this.location_city) {
    location_id = location_id;
    location_code = location_code;
    location_city = location_city;
    label = "$location_code - $location_city";
  }
  @override
  String toString() {
    return "$location_id - $location_code - $location_city";
  }
}

class Progetto {
  dynamic project_id;
  dynamic project_code;
  dynamic customer_code;
  String label = "";

  Progetto(this.project_id, this.project_code, this.customer_code) {
    project_id = project_id;
    project_code = project_code;
    customer_code = customer_code;
    label = "$project_code - $customer_code";
  }
  @override
  String toString() {
    return "$project_id - $project_code - $customer_code";
  }
}

class Attivita {
  dynamic project_task_id;
  dynamic project_task_code;
  dynamic project_code;
  dynamic customer_code;
  String label = "";

  Attivita(this.project_task_id, this.project_task_code, this.project_code,
      this.customer_code) {
    project_task_id = project_task_id;
    project_task_code = project_task_code;
    project_code = project_code;
    customer_code = customer_code;
    label = "$project_task_code - $project_code - $customer_code";
  }
  @override
  String toString() {
    return "$project_task_id - $project_task_code - $project_code -  $customer_code";
  }
}

class TipoAttivita {
  dynamic task_type_id;
  dynamic task_type_code;
  dynamic unity_code;
  String label = "";

  TipoAttivita(this.task_type_id, this.task_type_code, this.unity_code) {
    task_type_id = task_type_id;
    task_type_code = task_type_code;
    unity_code = unity_code;
    label = "$task_type_code - $unity_code";
  }
  @override
  String toString() {
    return "$task_type_id - $task_type_code - $unity_code";
  }
}

class Utente {
  dynamic user_id;
  dynamic username;
  dynamic signature;
  dynamic avatar;
  String label = "";

  Utente(this.user_id, this.username, this.signature, this.avatar) {
    user_id = user_id;
    username = username;
    signature = signature;
    avatar = avatar;
    label = "$username";
  }
  @override
  String toString() {
    return "$user_id - $username - $signature - $avatar";
  }
}

class Filterbox extends StatefulWidget {
  const Filterbox(
      {super.key,
      required this.fetchRep,
      required this.data,
      required this.aggiornaData});

  final Function fetchRep;
  final DateTime data;
  final Function aggiornaData;

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

class _FilterboxState extends State<Filterbox> {
  Future<void> clear() async {
    widget.aggiornaData();
  }

  List<Cliente> clienti = List.empty(growable: true);
  List<Luogo> luoghi = List.empty(growable: true);
  List<Progetto> progetti = List.empty(growable: true);
  List<Attivita> attivita = List.empty(growable: true);
  List<TipoAttivita> tipoAttivita = List.empty(growable: true);
  List<Utente> utenti = List.empty(growable: true);
  List<dynamic> selectedList = [];

  @override
  Widget build(BuildContext context) {
    var dataFetch = context.watch<DataFetch>();
    double screenWidth = MediaQuery.of(context).size.width;
    double screenHeight = MediaQuery.of(context).size.height;

    void openFilterDialog<T extends Object>(List<T> lista) async {
      print("Enter");
      setState(() {
        if (lista is List<Cliente>) {
          selectedList = dataFetch.customer as List<T>;
        } else if (lista is List<Luogo>) {
          selectedList = dataFetch.location as List<T>;
        } else if (lista is List<Progetto>) {
          selectedList = dataFetch.project as List<T>;
        } else if (lista is List<Attivita>) {
          selectedList = dataFetch.projectTask as List<T>;
        } else if (lista is List<TipoAttivita>) {
          selectedList = dataFetch.taskType as List<T>;
        } else if (lista is List<Utente>) {
          selectedList = dataFetch.user as List<T>;
        }
      });

      // print(selectedList.toString());

      await FilterListDialog.display<T>(
        applyButtonText: 'Applica',
        allButtonText: 'Tutti',
        themeData: FilterListThemeData(
          context,
          backgroundColor: Theme.of(context).colorScheme.surface,
          headerTheme: HeaderThemeData(
            backgroundColor: Theme.of(context).colorScheme.surface,
            closeIconColor: Theme.of(context).colorScheme.onSurface,
            searchFieldBackgroundColor: Theme.of(context).colorScheme.onSurface,
            searchFieldIconColor: Theme.of(context).colorScheme.surface,
            searchFieldHintText: 'Cerca...',
            searchFieldHintTextStyle: TextStyle(
                color: Theme.of(context).colorScheme.outline, fontSize: 18),
            searchFieldTextStyle: TextStyle(
                color: Theme.of(context).colorScheme.surface, fontSize: 18),
            headerTextStyle: TextStyle(
                color: Theme.of(context).colorScheme.onSurface,
                fontSize: 18,
                fontWeight: FontWeight.bold),
          ),
          controlButtonBarTheme: ControlButtonBarThemeData(
            context,
            backgroundColor: Theme.of(context).colorScheme.onSurface,
            controlButtonTheme: ControlButtonThemeData(
              primaryButtonBackgroundColor:
                  Theme.of(context).colorScheme.tertiaryContainer,
              primaryButtonTextStyle: TextStyle(
                color: Theme.of(context).colorScheme.onTertiaryContainer,
                fontSize: 15,
              ),
              textStyle: TextStyle(
                color: Theme.of(context).colorScheme.surface,
                fontSize: 15,
              ),
            ),
          ),
        ),
        context,
        listData: lista,
        selectedItemsText: 'Selezionati',
        selectedListData: selectedList as List<T>,
        choiceChipLabel: (item) => '',
        choiceChipBuilder: (context, item, isSelected) {
          // print(item);
          // print(isSelected);
          return Container(
              padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
              margin: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
              decoration: BoxDecoration(
                color: isSelected!
                    ? Theme.of(context).colorScheme.tertiaryContainer
                    : Theme.of(context).colorScheme.surface,
                borderRadius: BorderRadius.circular(10),
                border: Border.all(
                    color: isSelected
                        ? Theme.of(context).colorScheme.tertiaryContainer
                        : Theme.of(context).colorScheme.onSurface),
              ),
              child: Text(
                item.label,
                style: TextStyle(
                    color: isSelected
                        ? Theme.of(context).colorScheme.onTertiaryContainer
                        : Theme.of(context).colorScheme.onSurface,
                    fontSize: 15),
              ));
        },
        validateSelectedItem: (list, val) {
          print("CiAo");
          print(list);
          print(val);
          return list.toString().contains(val.toString());
        },
        /*validateRemoveItem: (list, item) {
          print(list);
          list!.remove(item);
          for (var ele in list) {
            if (ele.toString() == item.toString()) {
              list.remove(ele);
            }
          }
          print(list);
          return list;
        },*/
        onItemSearch: (ele, query) {
          if (ele is Cliente) {
            return ele.customer_code!
                    .toLowerCase()
                    .contains(query.toLowerCase()) ||
                ele.customer_companyname!
                    .toLowerCase()
                    .contains(query.toLowerCase());
          } else if (ele is Luogo) {
            return ele.location_code!
                    .toLowerCase()
                    .contains(query.toLowerCase()) ||
                ele.location_city!.toLowerCase().contains(query.toLowerCase());
          } else if (ele is Progetto) {
            return ele.project_code!
                    .toLowerCase()
                    .contains(query.toLowerCase()) ||
                ele.customer_code!.toLowerCase().contains(query.toLowerCase());
          } else if (ele is Attivita) {
            return ele.project_task_code!
                    .toLowerCase()
                    .contains(query.toLowerCase()) ||
                ele.project_code!.toLowerCase().contains(query.toLowerCase()) ||
                ele.customer_code!.toLowerCase().contains(query.toLowerCase());
          } else if (ele is TipoAttivita) {
            return ele.task_type_code!
                    .toLowerCase()
                    .contains(query.toLowerCase()) ||
                ele.unity_code!.toLowerCase().contains(query.toLowerCase());
          } else if (ele is Utente) {
            return ele.username!.toLowerCase().contains(query.toLowerCase());
          } else {
            return false;
          }
        },
        onApplyButtonClick: (list) {
          setState(() {
            if (list is List<Cliente>) {
              dataFetch.customer = list as List<Cliente>;
            } else if (list is List<Luogo>) {
              dataFetch.location = list as List<Luogo>;
            } else if (list is List<Progetto>) {
              dataFetch.project = list as List<Progetto>;
            } else if (list is List<Attivita>) {
              dataFetch.projectTask = list as List<Attivita>;
            } else if (list is List<TipoAttivita>) {
              dataFetch.taskType = list as List<TipoAttivita>;
            } else if (list is List<Utente>) {
              dataFetch.user = list as List<Utente>;
            }
          });
          selectedList = list!;
          Navigator.pop(context);
        },
      );
    }

    return Wrap(
      children: [
        Container(
          decoration: BoxDecoration(
            borderRadius: const BorderRadius.only(
                topLeft: Radius.circular(25), topRight: Radius.circular(25)),
            color: Theme.of(context).colorScheme.tertiaryContainer,
          ),
          child: Padding(
            padding: const EdgeInsets.symmetric(vertical: 20),
            child: Column(
              children: [
                SizedBox(
                  height: screenHeight / 100 * 1,
                ),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 20),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Text(
                        'FILTRA PER:',
                        style: TextStyle(
                            color: Colors.white,
                            fontSize:
                                MediaQuery.of(context).size.height / 100 * 2.5,
                            fontWeight: FontWeight.bold),
                      ),
                      IconButton(
                          onPressed: () {
                            Navigator.pop(context);
                          },
                          icon: const Icon(
                            Icons.close,
                            color: Colors.white,
                          ))
                    ],
                  ),
                ),
                SizedBox(
                  height: screenHeight / 100 * 2.5,
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    Column(
                      children: [
                        Container(
                            width: screenWidth / 100 * 37,
                            alignment: Alignment.centerLeft,
                            child: const Text('TIPO',
                                textAlign: TextAlign.left,
                                style: TextStyle(
                                    color: Colors.white,
                                    fontWeight: FontWeight.bold,
                                    fontSize: 18))),
                        const SizedBox(
                          height: 7,
                        ),
                        DropdownMenu<String>(
                          inputDecorationTheme: InputDecorationTheme(
                              fillColor: Theme.of(context).colorScheme.tertiary,
                              filled: true,
                              border: const OutlineInputBorder(
                                  borderSide: BorderSide.none,
                                  borderRadius:
                                      BorderRadius.all(Radius.circular(10)))),
                          textStyle: const TextStyle(
                              color: Colors.white, fontWeight: FontWeight.bold),
                          width: screenWidth / 100 * 40,
                          trailingIcon: const Icon(Icons.arrow_drop_down,
                              color: Colors.white),
                          selectedTrailingIcon: const Icon(
                            Icons.arrow_drop_up,
                            color: Colors.white,
                          ),
                          initialSelection: dataFetch.type,
                          dropdownMenuEntries: const [
                            DropdownMenuEntry(value: '', label: ''),
                            DropdownMenuEntry(value: 'R', label: 'Rapportino'),
                            DropdownMenuEntry(value: 'E', label: 'Evento'),
                          ],
                          onSelected: (value) async {
                            List<List<DateTime>> weeks =
                                getWeeksOfMonth(widget.data);

                            dataFetch.type = value ?? '';

                            clear().then((val) {
                              widget.fetchRep(
                                  first: weeks.first.first,
                                  last: weeks.last.last,
                                  type: value ?? '');
                            });
                          },
                        ),
                      ],
                    ),
                    Column(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        Container(
                            width: screenWidth / 100 * 37,
                            alignment: Alignment.centerLeft,
                            child: const Text('CLIENTE',
                                textAlign: TextAlign.left,
                                style: TextStyle(
                                    color: Colors.white,
                                    fontWeight: FontWeight.bold,
                                    fontSize: 18))),
                        const SizedBox(
                          height: 7,
                        ),
                        SizedBox(
                          width: screenWidth / 100 * 40,
                          child: TextField(
                            readOnly: true,
                            style: const TextStyle(
                                color: Colors.white,
                                fontWeight: FontWeight.bold),
                            decoration: InputDecoration(
                              fillColor: Theme.of(context).colorScheme.tertiary,
                              filled: true,
                              suffixIcon: const Icon(
                                Icons.arrow_drop_down,
                                color: Colors.white,
                              ),
                              border: const OutlineInputBorder(
                                borderSide: BorderSide.none,
                                borderRadius:
                                    BorderRadius.all(Radius.circular(10)),
                              ),
                            ),
                            onTap: () {
                              if (clienti.isEmpty) {
                                Service()
                                    .selectRead(sesid: globals.sesid, tipo: "C")
                                    .then((res) {
                                  clienti.clear();
                                  var body = jsonDecode(res.body);
                                  var data = body["data"];

                                  // ignore: avoid_print
                                  for (var element in data) {
                                    clienti.add(Cliente(
                                        element["customer_id"],
                                        element["customer_code"],
                                        element["customer_companyname"]));
                                  }
                                  openFilterDialog(clienti);
                                });
                              } else {
                                openFilterDialog(clienti);
                              }
                            },
                          ),
                        ),
                      ],
                    ),
                  ],
                ),
                SizedBox(
                  height: screenHeight / 100 * 2.5,
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    Column(
                      children: [
                        Container(
                            width: screenWidth / 100 * 37,
                            alignment: Alignment.centerLeft,
                            child: const Text('LUOGO',
                                textAlign: TextAlign.left,
                                style: TextStyle(
                                    color: Colors.white,
                                    fontWeight: FontWeight.bold,
                                    fontSize: 18))),
                        const SizedBox(
                          height: 7,
                        ),
                        SizedBox(
                          width: screenWidth / 100 * 40,
                          child: TextField(
                            readOnly: true,
                            style: const TextStyle(
                                color: Colors.white,
                                fontWeight: FontWeight.bold),
                            decoration: InputDecoration(
                              fillColor: Theme.of(context).colorScheme.tertiary,
                              filled: true,
                              suffixIcon: const Icon(
                                Icons.arrow_drop_down,
                                color: Colors.white,
                              ),
                              border: const OutlineInputBorder(
                                borderSide: BorderSide.none,
                                borderRadius:
                                    BorderRadius.all(Radius.circular(10)),
                              ),
                            ),
                            onTap: () {
                              if (luoghi.isEmpty) {
                                Service()
                                    .selectRead(sesid: globals.sesid, tipo: "L")
                                    .then((res) {
                                  var body = jsonDecode(res.body);
                                  var data = body["data"];
                                  // ignore: avoid_print
                                  for (var element in data) {
                                    luoghi.add(Luogo(
                                        element["locatio_id"],
                                        element["location_code"],
                                        element["location_city"]));
                                  }
                                  openFilterDialog(luoghi);
                                });
                              } else {
                                openFilterDialog(luoghi);
                              }
                            },
                          ),
                        ),
                      ],
                    ),
                    Column(
                      children: [
                        Container(
                            width: screenWidth / 100 * 37,
                            alignment: Alignment.centerLeft,
                            child: const Text('PROGETTO',
                                textAlign: TextAlign.left,
                                style: TextStyle(
                                    color: Colors.white,
                                    fontWeight: FontWeight.bold,
                                    fontSize: 18))),
                        const SizedBox(
                          height: 7,
                        ),
                        SizedBox(
                          width: screenWidth / 100 * 40,
                          child: TextField(
                            readOnly: true,
                            style: const TextStyle(
                                color: Colors.white,
                                fontWeight: FontWeight.bold),
                            decoration: InputDecoration(
                              fillColor: Theme.of(context).colorScheme.tertiary,
                              filled: true,
                              suffixIcon: const Icon(
                                Icons.arrow_drop_down,
                                color: Colors.white,
                              ),
                              border: const OutlineInputBorder(
                                borderSide: BorderSide.none,
                                borderRadius:
                                    BorderRadius.all(Radius.circular(10)),
                              ),
                            ),
                            onTap: () {
                              if (progetti.isEmpty) {
                                Service()
                                    .selectRead(sesid: globals.sesid, tipo: "P")
                                    .then((res) {
                                  var body = jsonDecode(res.body);
                                  var data = body["data"];
                                  // ignore: avoid_print
                                  for (var element in data) {
                                    progetti.add(Progetto(
                                        element["project_id"],
                                        element["project_code"],
                                        element["customer_code"]));
                                  }
                                  openFilterDialog(progetti);
                                });
                              } else {
                                openFilterDialog(progetti);
                              }
                            },
                          ),
                        ),
                      ],
                    ),
                  ],
                ),
                SizedBox(
                  height: screenHeight / 100 * 2.5,
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    Column(
                      children: [
                        Container(
                            width: screenWidth / 100 * 37,
                            alignment: Alignment.centerLeft,
                            child: const Text('ATTIVITÀ',
                                textAlign: TextAlign.left,
                                style: TextStyle(
                                    color: Colors.white,
                                    fontWeight: FontWeight.bold,
                                    fontSize: 18))),
                        const SizedBox(
                          height: 7,
                        ),
                        SizedBox(
                          width: screenWidth / 100 * 40,
                          child: TextField(
                            readOnly: true,
                            style: const TextStyle(
                                color: Colors.white,
                                fontWeight: FontWeight.bold),
                            decoration: InputDecoration(
                              fillColor: Theme.of(context).colorScheme.tertiary,
                              filled: true,
                              suffixIcon: const Icon(
                                Icons.arrow_drop_down,
                                color: Colors.white,
                              ),
                              border: const OutlineInputBorder(
                                borderSide: BorderSide.none,
                                borderRadius:
                                    BorderRadius.all(Radius.circular(10)),
                              ),
                            ),
                            onTap: () {
                              if (attivita.isEmpty) {
                                Service()
                                    .selectRead(sesid: globals.sesid, tipo: "A")
                                    .then((res) {
                                  var body = jsonDecode(res.body);
                                  var data = body["data"];
                                  // ignore: avoid_print
                                  for (var element in data) {
                                    attivita.add(Attivita(
                                        element["project_task_id"],
                                        element["project_task_code"],
                                        element["project_code"],
                                        element["customer_code"]));
                                  }
                                  openFilterDialog(attivita);
                                });
                              } else {
                                openFilterDialog(attivita);
                              }
                            },
                          ),
                        ),
                      ],
                    ),
                    Column(
                      children: [
                        Container(
                            width: screenWidth / 100 * 37,
                            alignment: Alignment.centerLeft,
                            child: const Text('TIPO ATTIVITÀ',
                                textAlign: TextAlign.left,
                                style: TextStyle(
                                    color: Colors.white,
                                    fontWeight: FontWeight.bold,
                                    fontSize: 18))),
                        const SizedBox(
                          height: 7,
                        ),
                        SizedBox(
                          width: screenWidth / 100 * 40,
                          child: TextField(
                            readOnly: true,
                            style: const TextStyle(
                                color: Colors.white,
                                fontWeight: FontWeight.bold),
                            decoration: InputDecoration(
                              fillColor: Theme.of(context).colorScheme.tertiary,
                              filled: true,
                              suffixIcon: const Icon(
                                Icons.arrow_drop_down,
                                color: Colors.white,
                              ),
                              border: const OutlineInputBorder(
                                borderSide: BorderSide.none,
                                borderRadius:
                                    BorderRadius.all(Radius.circular(10)),
                              ),
                            ),
                            onTap: () {
                              if (tipoAttivita.isEmpty) {
                                Service()
                                    .selectRead(
                                        sesid: globals.sesid, tipo: "TA")
                                    .then((res) {
                                  var body = jsonDecode(res.body);
                                  var data = body["data"];

                                  // ignore: avoid_print
                                  for (var element in data) {
                                    tipoAttivita.add(TipoAttivita(
                                        element["task_type_id"],
                                        element["task_type_code"],
                                        element["unity_code"]));
                                  }
                                  openFilterDialog(tipoAttivita);
                                });
                              } else {
                                openFilterDialog(tipoAttivita);
                              }
                            },
                          ),
                        ),
                      ],
                    ),
                  ],
                ),
                SizedBox(
                  height: screenHeight / 100 * 2.5,
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    Column(
                      children: [
                        Container(
                            width: screenWidth / 100 * 75,
                            alignment: Alignment.centerLeft,
                            child: const Text('UTENTE',
                                textAlign: TextAlign.left,
                                style: TextStyle(
                                    color: Colors.white,
                                    fontWeight: FontWeight.bold,
                                    fontSize: 18))),
                        const SizedBox(
                          height: 7,
                        ),
                        SizedBox(
                          width: screenWidth / 100 * 80,
                          child: TextField(
                            readOnly: true,
                            style: const TextStyle(
                                color: Colors.white,
                                fontWeight: FontWeight.bold),
                            decoration: InputDecoration(
                              fillColor: Theme.of(context).colorScheme.tertiary,
                              filled: true,
                              suffixIcon: const Icon(
                                Icons.arrow_drop_down,
                                color: Colors.white,
                              ),
                              border: const OutlineInputBorder(
                                borderSide: BorderSide.none,
                                borderRadius:
                                    BorderRadius.all(Radius.circular(10)),
                              ),
                            ),
                            onTap: () {
                              if (utenti.isEmpty) {
                                Service()
                                    .selectRead(sesid: globals.sesid, tipo: "U")
                                    .then((res) {
                                  var body = jsonDecode(res.body);
                                  var data = body["data"];

                                  // ignore: avoid_print
                                  for (var element in data) {
                                    utenti.add(Utente(
                                        element["user_id"],
                                        element["username"],
                                        element["signature"],
                                        element["avatar"]));
                                  }
                                  openFilterDialog(utenti);
                                });
                              } else {
                                openFilterDialog(utenti);
                              }
                            },
                          ),
                        ),
                      ],
                    ),
                  ],
                ),
                SizedBox(
                  height: screenHeight / 100 * 2.5,
                ),
              ],
            ),
          ),
        ),
      ],
    );
  }
}
Giacomo-Cattani commented 2 months ago

I am posting here after some days of testing. Continuing to test, I found a possible fix. I modified validateRemoveItem by casting the returned list, and it seems to have resolved the problem.

Solution Code:

validateRemoveItem: (list, item) {
         list!.remove(item);
          for (var ele in list) {
            if (ele.toString() == item.toString()) {
              list.remove(ele);
              break;
            }
          }
          return list.cast<T>();
},