Coder Social home page Coder Social logo

thealphamerc / flutter_plugin_filter_list Goto Github PK

View Code? Open in Web Editor NEW
204.0 9.0 66.0 4.36 MB

filterList is a flutter package which provide utility to search/filter data from provided dynamic list.

Home Page: https://pub.dev/packages/filter_list

License: BSD 2-Clause "Simplified" License

Swift 1.04% Objective-C 0.02% Dart 70.53% HTML 1.11% Kotlin 0.07% CMake 11.71% C++ 14.32% C 0.86% Shell 0.33%

flutter_plugin_filter_list's Issues

Maximum selectable Chips

Hello,

it will be great to get control of a maximum amount of selectable Chips. Like the [maxLength] propertie in TextFields.

Filter By date

Add Filter By Date feature If Exist
In Between range of Start and End dates

Merging Duplicate Items in Choice Chip into 1

Is your feature request related to a problem? Please describe.

currently, If we have duplicates in the choice chip, filter list still shows the duplicate.

Describe the solution you'd like

it would be great if we have option to merge duplicate items into 1.

How do I trigger the removeSelectedItem(item) method in a sibling of the FilterListWidget component on the same page and refresh the FilterListWidget

How do I trigger the removeSelectedItem(item) method in a sibling of the FilterListWidget component on the same page and refresh the FilterListWidget

image
  textfield_tags: ^2.0.2
  #filter_list: ^1.0.2
  filter_list:
    path: plugin/flutter_plugin_filter_list

page_view.dart

import 'package:filter_list/filter_list.dart';
import 'package:fluent_ui/fluent_ui.dart' as fl;
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:imboy/component/helper/list.dart';
import 'package:imboy/component/ui/common_bar.dart';
import 'package:imboy/component/ui/tag.dart';
import 'package:imboy/config/const.dart';
import 'package:niku/namespace.dart' as n;
import 'package:textfield_tags/textfield_tags.dart';

import 'tag_add_logic.dart';

// ignore: must_be_immutable
class TagAddPage extends StatelessWidget {
  final String peerId; // 用户ID

  String peerTag;
  final Color tagBackgroundColor;
  final Color tagSelectedBackgroundColor;

  TagAddPage({
    super.key,
    required this.peerId,
    required this.peerTag,
    this.tagBackgroundColor = const Color(0xfff8f8f8),
    this.tagSelectedBackgroundColor = const Color(0xFF649BEC),
  });

  @override
  Widget build(BuildContext context) {
    final logic = Get.put(TagAddLogic());
    final state = Get.find<TagAddLogic>().state;
    state.tagItems.value =
        peerTag.split(',').where((o) => o.trim().isNotEmpty).toList();
    for (var item in state.tagItems) {
      if (!state.recentTagItems.contains(item)) {
        state.recentTagItems.add(item);
      }
    }
    state.tagController.addListener(() {
      bool diff =
          listDiff(state.tagItems.toList(), state.tagController.getTags);
      state.tagItems.value = state.tagController.getTags!;
      // state.tagController.setError = '';
      // debugPrint(
      //     "tag_add_view_tagsController_addListener $diff tagItems ${state.tagItems.value.toList().toString()}");
      // debugPrint(
      //     "tag_add_view_tagsController_addListener $diff getTags ${state.tagController.getTags.toString()}");
      logic.valueOnChange(diff);
      if (diff) {
        state.tagController.setError = '需要确认提交,该操作才生效'.tr;
      }
    });
    return Scaffold(
      backgroundColor: AppColors.ChatBg,
      // backgroundColor: Colors.white,
      appBar: PageAppBar(
        titleWidget: n.Row(
          [
            Expanded(
              child: Text(
                '添加标签'.tr,
                textAlign: TextAlign.center,
                style: const TextStyle(
                  fontSize: 16.0,
                  fontWeight: FontWeight.bold,
                ),
              ),
              // 中间用Expanded控件
            ),
            ElevatedButton(
              onPressed: () async {
                //
              },
              // ignore: sort_child_properties_last
              child: Text(
                '新建'.tr,
                textAlign: TextAlign.center,
              ),
              style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all<Color>(
                  // AppColors.primaryElement,
                  tagSelectedBackgroundColor,
                ),
                foregroundColor: MaterialStateProperty.all<Color>(
                  Colors.white,
                ),
                minimumSize: MaterialStateProperty.all(const Size(60, 40)),
                visualDensity: VisualDensity.compact,
                padding: MaterialStateProperty.all(EdgeInsets.zero),
              ),
            ),
          ],
        ),
      ),
      body: fl.FluentTheme(
        data: fl.FluentThemeData(),
        child: n.Padding(
          left: 12,
          top: 12,
          right: 12,
          child: n.Column(
            [
              TextFieldTags(
                // key: Key('TextFieldTags'),
                // textEditingController: ,
                // focusNode: tfn,
                textfieldTagsController: state.tagController,
                initialTags: state.tagItems,
                textSeparators: const [' ', ','],
                // textSeparators: const [','],
                letterCase: LetterCase.normal,
                validator: (String tag) {
                  bool diff =
                      listDiff(state.tagItems, state.tagController.getTags);
                  debugPrint(
                      "tag_add_view_validator diff $diff, $tag, len:${tag.length}");
                  logic.valueOnChange(diff);
                  if (tag.length > 14) {
                    // 最最最最最最最最最最最最最最1
                    return '最多14个字'.tr;
                  }
                  if (state.tagController.getTags != null &&
                      state.tagController.getTags!.contains(tag)) {
                    // return 'you already entered that';
                    return '你已经输入过了'.tr;
                  }
                  return null;
                },

                inputfieldBuilder: (context, tecController, fn, error,
                    onChanged, onSubmitted) {
                  return ((context, scController, tags, onTagDelete) {
                    return Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 10.0),
                      child: TextField(
                        controller: tecController,
                        focusNode: fn,
                        decoration: InputDecoration(
                          border: UnderlineInputBorder(
                            borderSide: BorderSide(
                                color: tagSelectedBackgroundColor, width: 1.0),
                          ),
                          focusedBorder: UnderlineInputBorder(
                            borderSide: BorderSide(
                                color: tagSelectedBackgroundColor, width: 1.0),
                          ),
                          // helperText: '全部标签'.tr,
                          helperStyle: TextStyle(
                            color: tagSelectedBackgroundColor,
                          ),
                          hintText:
                              state.tagController.hasTags ? '' : '选择或输入标签'.tr,
                          errorText: error,
                          prefixIconConstraints: BoxConstraints(
                              maxWidth: state.distanceToField * 1.0),
                          prefixIcon: tags.isNotEmpty
                              ? SingleChildScrollView(
                                  controller: scController,
                                  scrollDirection: Axis.horizontal,
                                  child: n.Row(tags.map((String tag) {
                                    return TagItem(
                                      tag: tag,
                                      onTagDelete: (String tag) {
                                        debugPrint(
                                            "tag_add_page_onTagDelete $tag");
                                        onTagDelete(tag);
                                        // Get.find<FilterState>().removeSelectedItem(tag);
                                        // final state = StateProvider.of<FilterState<String>>(context);
                                        // state.removeSelectedItem(tag);
                                      },
                                      backgroundColor: tagBackgroundColor,
                                      selectedBackgroundColor:
                                          tagSelectedBackgroundColor,
                                    );
                                  }).toList()),
                                )
                              : null,
                        ),
                        onChanged: onChanged,
                        onSubmitted: onSubmitted,
                      ),
                    );
                  });
                },
              ),
              n.Padding(
                top: 10,
                child: fl.SizedBox(
                  height: Get.height - 160,
                  child: FilterListWidget<String>(
                    resetButtonText: '置空'.tr,
                    applyButtonText: '确认'.tr,
                    hideHeader: true,
                    enableOnlySingleSelection: false,
                    listData: state.recentTagItems,
                    selectedListData: state.tagItems,
                    controlButtons: const [ControlButtonType.Reset],
                    themeData: FilterListThemeData(
                      context,
                      backgroundColor: AppColors.ChatBg,
                      choiceChipTheme: ChoiceChipThemeData(
                        backgroundColor: tagBackgroundColor,
                        selectedBackgroundColor: tagSelectedBackgroundColor,
                      ),
                    ),
                    onApplyButtonClick: (list) async {
                      List<String>? tag =
                          state.tagController.getTags?.toSet().toList();
                      // state.tagController.getTags = tag?.toList();
                      debugPrint(
                          "submit_tag ${tag?.length} ${tag.toString()}, ");
                      bool res = await logic.add(peerId, tag ?? []);
                      if (res) {
                        // EasyLoading.showSuccess('操作成功'.tr);
                        Get.back(result: tag!.join(','));
                      }
                    },
                    choiceChipLabel: (item) {
                      /// Used to display text on chip

                      debugPrint(
                          "tag_add_page_choiceChipLabel $item, ${state.tagItems.contains(item)}");
                      return item;
                    },
                    validateSelectedItem: (list, val) {
                      ///  identify if item is selected or not
                      debugPrint(
                          "tag_add_page_validateSelectedItem $val, ${list!.contains(val)}, ${list.toString()}");
                      // if (list.contains(val)) {
                      //   state.tagController.addTag = val;
                      // }

                      return list.contains(val);
                    },
                    onReset: () {
                      state.tagController.clearTags();

                      state.tagController.setError = '需要确认提交,该操作才生效'.tr;
                      debugPrint(
                          "tag_add_page_onReset ${state.tagController.getTags?.length}");

                      /// When search query change in search bar then this method will be called
                      ///
                      // return true;
                    },
                    onSelected: (String item, bool selected) {
                      if (selected) {
                        state.tagController.addTag = item;
                      } else {
                        state.tagController.removeTag = item;
                        state.tagItems.value = state.tagController.getTags!;
                      }
                      // debugPrint("tag_add_page_onSelected $selected, $item, index $index");
                      state.tagController.notifyListeners();
                    },
                  ),
                ),
              ),
            ],
            // 内容文本左对齐
            crossAxisAlignment: CrossAxisAlignment.start,
          ),
        ),
      ),
    );
  }
}

Error: Type 'ListTileThemeData' not found - When compiling on Macos

Describe the bug
Failed to compile this library on macos (m1) Monterey 12.0.1
Here are the errors I get when I use this library, but when I comment out the usage its working just fine.

Launching lib/main.dart on Chrome in debug mode...
Waiting for connection from debug service on Chrome...
../../Downloads/flutter/.pub-cache/hosted/pub.dartlang.org/filter_list-1.0.1/lib/src/theme/filter_list_delegate_theme.dart:37:5: Error: Type 'ListTileThemeData' not found.
    ListTileThemeData? listTileTheme,
    ^^^^^^^^^^^^^^^^^
../../Downloads/flutter/.pub-cache/hosted/pub.dartlang.org/filter_list-1.0.1/lib/src/theme/filter_list_delegate_theme.dart:84:9: Error: Type 'ListTileThemeData' not found.
  final ListTileThemeData listTileTheme;
        ^^^^^^^^^^^^^^^^^
../../Downloads/flutter/.pub-cache/hosted/pub.dartlang.org/filter_list-1.0.1/lib/src/filter_list_delegate.dart:252:27: Error: No named parameter with the name 'data'.
                          data: theme.listTileTheme,
                          ^^^^
../../Downloads/flutter/packages/flutter/lib/src/material/list_tile.dart:44:9: Context: Found this candidate, but the arguments don't match.
  const ListTileTheme({
        ^^^^^^^^^^^^^
../../Downloads/flutter/.pub-cache/hosted/pub.dartlang.org/filter_list-1.0.1/lib/src/filter_list_delegate.dart:260:27: Error: No named parameter with the name 'data'.
                          data: theme.listTileTheme,
                          ^^^^
../../Downloads/flutter/packages/flutter/lib/src/material/list_tile.dart:44:9: Context: Found this candidate, but the arguments don't match.
  const ListTileTheme({
        ^^^^^^^^^^^^^
../../Downloads/flutter/.pub-cache/hosted/pub.dartlang.org/filter_list-1.0.1/lib/src/theme/filter_list_delegate_theme.dart:37:5: Error: 'ListTileThemeData' isn't a type.
    ListTileThemeData? listTileTheme,
    ^^^^^^^^^^^^^^^^^
../../Downloads/flutter/.pub-cache/hosted/pub.dartlang.org/filter_list-1.0.1/lib/src/theme/filter_list_delegate_theme.dart:51:23: Error: Method not found: 'ListTileThemeData'.
    listTileTheme ??= ListTileThemeData();
                      ^^^^^^^^^^^^^^^^^
../../Downloads/flutter/.pub-cache/hosted/pub.dartlang.org/filter_list-1.0.1/lib/src/theme/filter_list_delegate_theme.dart:84:9: Error: 'ListTileThemeData' isn't a type.
  final ListTileThemeData listTileTheme;
        ^^^^^^^^^^^^^^^^^
../../Downloads/flutter/.pub-cache/hosted/pub.dartlang.org/filter_list-1.0.1/lib/src/theme/filter_list_delegate_theme.dart:97:33: Error: 'ListTileThemeData' isn't a type.
      ..add(DiagnosticsProperty<ListTileThemeData>(
                                ^^^^^^^^^^^^^^^^^
../../Downloads/flutter/.pub-cache/hosted/pub.dartlang.org/filter_list-1.0.1/lib/src/theme/filter_list_delegate_theme.dart:102:33: Error: 'ListTileThemeData' isn't a type.
      ..add(DiagnosticsProperty<ListTileThemeData>(
                                ^^^^^^^^^^^^^^^^^

To Reproduce
Steps to reproduce the behavior:

  1. Here is my only usage of it in my app
await FilterListDialog.display<RequestDBModel>(
      context,
      listData: distinctRequests,
      selectedListData: selectedRequests,
      choiceChipLabel: getFilteredFieldAsString,
      validateSelectedItem: (list, val) => list!.contains(val),
      onItemSearch: (request, query) {
        return getFilteredFieldAsString(request)
            .toLowerCase()
            .contains(query.toLowerCase());
      },
      selectedItemsText:
          AppDynamicLocalizations.of(context)?.translate("selecteditems") ??
              'selected items',
      allButtonText:
          AppDynamicLocalizations.of(context)?.translate("all") ?? 'All',
      applyButtonText:
          AppDynamicLocalizations.of(context)?.translate("apply") ?? 'Apply',
      resetButtonText:
          AppDynamicLocalizations.of(context)?.translate("reset") ?? 'Reset',
      onApplyButtonClick: (list) {
        setState(() {
          filtersByColumn[columnIndex] = [];
          if (list?.length != distinctRequests.length) {
            // If actually choose all(no need to filter it at all)
            list?.forEach((request) {
              filtersByColumn[columnIndex]
                  .add(getFilteredFieldAsString(request));
            });
          }
        });
        Navigator.pop(context);
      },
    );

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: macos (m1) Monterey 12.0.1 (On windows it works great)
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: Compiled to web
  • Browser chrome

Remove bottom Bar Or just remove Apply button.

i just don't want the apply button but i cant get rid of it.

The most easy way is just inculde the apply button in the "controlButtons" list.

Or just remove the whole bar together because i dont want any buttons.

Screenshot 2022-12-05 at 10 19 18

Flutter upgrade to 3.22 and Getting Error for TextTheme Caption.

/C:/Users/xxx/AppData/Local/Pub/Cache/hosted/pub.dev/filter_list-1.0.2/lib/src/filter_list_widget.dart:193:58: Error: The getter 'caption' isn't defined for the class 'TextTheme'.

  • 'TextTheme' is from 'package:flutter/src/material/text_theme.dart' ('/D:/flutter/packages/flutter/lib/src/material/text_theme.dart').
    Try correcting the name to the name of an existing getter, or defining a getter or field named 'caption'.
    style: Theme.of(context).textTheme.caption,
    ^^^^^^^
    Target kernel_snapshot failed: Exception

After upgrading to Flutter 3.22.
Getting textTheme.caption error when compiling.

Disabling "All" and "Reset" buttons

Is your feature request related to a problem? Please describe.
It would be very nice to be able to remove the "all" and "reset" buttons.

Describe the solution you'd like
A parameter in the constructor to allow you to remove the "all" and "reset" buttons if desired. If removed, the "Accept" button should be the only one remaining and could be automatically centred to the bottom middle.

Describe alternatives you've considered
I have tried removing the text from the button (using "resetButtonText" and "allButtonText"), but it's still showing the buttons. Maybe giving an empty string ("") could disable it.

Additional context
I am using the widget as a tag selector while in the creation of elements for my app, and it makes no sense to have the "all" button, I wouldn't want the users to set all the tags to a new element, usually they should add only 2-3.

[Bug] FilterListDelegate bug when select item

Describe the bug
In FilterListDelegate mode, when I select the item, the item that is not visible is already selected (usually on the 2nd attempt). however when i click on the search box the item shows as selected.

To Reproduce
Steps to reproduce the behavior:

  1. Select item -> not show selected (usually on the 2nd attempt).
  2. Click on the search box -> show selected.

Expected behavior
Item show selected when select.

Screenshots
Bug

Smartphone

  • Device: [Samsung M51]
  • OS: [Android 12]

[Question] initial selected

at initstate I've done to add selectedlistdate

but when i clicked the filter list, the filterlistdelegate not giving the checklist.

image

am i wrong to write below code ?
image

btw ive logs the list that i input into the selectedlist.
it show, but only at the filterlistdelegate that not giving the checklist

Customise close button on a dialog

Is your feature request related to a problem? Please describe.
It would be good to add option to customise close button appearance in order to make it consistent with the rest of application. There is already an option to customise close icon color, however it's not currently possible to change the icon itself.

Describe the solution you'd like
A builder for delivering the button would be perfect.

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

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:

Video.mp4

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,
                ),
              ],
            ),
          ),
        ),
      ],
    );
  }
}

Multiple Chips with Same Value

Describe the bug
Using this plugin I am trying to group results based on locations, but for every repeated Location the plugin treats it as a different entity, hence shows a different chip for the same.

To Reproduce
Steps to reproduce the behavior:
A list with objects having fields : id (string: unique), name: (string: unique), location (string: repeated).
I want to use the filter on location.

Expected behavior
The plugin should group all location objects together and show the result

Screenshots
image

Additional context
The example App provided does not have repeated values in the array, is this the default behavior of the plugin.
If there is anyway I can group similar objects together using this plugin then help me out.

FilterListDelegateThemeData does not apply changed theme data

FilterListDelegate single selection text color cannot be changed from the default black.
I tried styling the text using FilterListDelegateThemeData but the theme changes aren't applied.
Am i supposed to style the list text in a different way??

Add paging or scroll controller

** Is your feature request related to a problem? Please describe.
Currently, the library lacks efficient support for handling large datasets or long lists, leading to potential performance issues and user frustration. Scrolling through extensive content or implementing pagination without a dedicated controller can result in suboptimal user experiences.

** Describe the solution you'd like
I propose the addition of a paging or scroll controller to the library. This controller would manage the loading and display of content in a more organized and performance-friendly manner. With this feature, users could smoothly navigate through large datasets or lengthy lists, enhancing the overall user experience.

** Describe alternatives you've considered

Manual Implementation: Users could manually implement their own pagination or scrolling logic, but this approach is prone to errors, increases development time, and may result in inconsistent experiences across different implementations.

** Additional context
To illustrate the need for this feature, consider scenarios where the library is used in applications dealing with extensive data, such as social media feeds, image galleries, or news articles. The addition of a paging or scroll controller would significantly improve the library's versatility and performance in handling such cases.

Support creation

Is your feature request related to a problem? Please describe.
When adding for example labels using this control, to be able to create item, not only select from existing.

Describe the solution you'd like
Type name of Chip item, and press Enter (or button) to create.

Describe alternatives you've considered
n/a

Additional context
n/a

Null check operator used on a null value

Describe the bug
A clear and concise description of what the bug is.

    await FilterListDialog.display<T>(
      this,
      listData: data,
      choiceChipLabel: (T? data) => titleBuilder?.call(data),
      validateSelectedItem: selectedDataValidator,
      onItemSearch: (T data, String query) =>
          searchComparator?.call(data, query) ??
          titleBuilder
              ?.call(data)
              ?.toLowerCase()
              .contains(query.toLowerCase()) ??
          false,
      hideSelectedTextCount: true,
      hideSearchField: true,
      allButtonText: MaterialLocalizations.of(this).selectAllButtonLabel,
      resetButtonText: 'reset'.translateAction(),
      applyButtonText: MaterialLocalizations.of(this).saveButtonLabel,
      onApplyButtonClick: (List<T>? data) => _completer.complete(data),
    );


======== Exception caught by gesture ===============================================================
The following _CastError was thrown while handling a gesture:
Null check operator used on a null value

When the exception was thrown, this was the stack: 
#0      FilterState.addSelectedItem (package:filter_list/src/state/filter_state.dart:46:18)
#1      ChoiceList._buildChoiceList.<anonymous closure>.<anonymous closure> (package:filter_list/src/widget/choice_list.dart:52:25)
#2      _RawChipState._handleTap (package:flutter/src/material/chip.dart:1716:24)
#3      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:989:21)
#4      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:198:24)
#5      TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:608:11)
#6      BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:296:5)
#7      BaseTapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:267:7)
#8      GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:157:27)
#9      GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:443:20)
#10     GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:419:22)
#11     RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:322:11)
#12     GestureBinding._handlePointerEventImmediately (package:flutter/src/gestures/binding.dart:374:7)
#13     GestureBinding.handlePointerEvent (package:flutter/src/gestures/binding.dart:338:5)
#14     GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:296:7)
#15     GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:279:7)
#19     _invoke1 (dart:ui/hooks.dart:170:10)
#20     PlatformDispatcher._dispatchPointerDataPacket (dart:ui/platform_dispatcher.dart:331:7)
#21     _dispatchPointerDataPacket (dart:ui/hooks.dart:94:31)
(elided 3 frames from dart:async)
Handler: "onTap"
Recognizer: TapGestureRecognizer#f56cc
  debugOwner: GestureDetector
  state: ready
  won arena
  finalPosition: Offset(153.4, 286.0)
  finalLocalPosition: Offset(34.2, 16.0)
  button: 1
  sent tap down
====================================================================================================

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

 // Add item in to selected list
  void addSelectedItem(K item) {
    _selctedItems!.add(item); // _selctedItems wasn't initialized

    notifyListeners();
  }

  // Remove item from selected list
  void removeSelectedItem(K item) {
    _selctedItems!.remove(item);

    notifyListeners();
  }

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

Apply button overflow on the right

Hey mate,

Thanks for this lib, made my life super easy as I'm just mocking up something which needs a filter.
I am getting some overflow reporting on the apply button.
"A RenderFlex overflowed by 234 pixels on the right."

I am on an Android Moto g6,
I can fix it for my case by setting the width, but I'm hesitant to use that to resolve it for a real multi platform / device experience.

Maybe id like to do something like setting the margin myself, or enabling the text to auto scale to the device I am on?

image

Thanks again!

Boa noite!

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

[Question] FilterListDialog.display is missing i18n parameters for "searchFieldHintText"

I am using your package and it is awesome. Thank you a lot for it :)

Actually, in the Code documentation I can see that it should be possible to set a string for the searchFieldHintText:
grafik

But when I initialize the Dialog with FilterListDialog there is no possibility to set the string. Actually the search string is still showing up in english language.
grafik

Will be there a fix?

Option to Remove The Shadow in FilterList Content Area

Is your feature request related to a problem? Please describe.
Currently Filterlist does have default shadow in Content Area That doesn't Go with My Apps Design Language, Please have an Option to Disable That

Describe the solution you'd like
Add Boolean to Turn that Default Shadow ON and OFF, for ex HideContentAreaShadow

Additional context

Here's Image that represent Default Shadow on Content Area

Inkedscreenshot_6

[Question] Change title apply button & title search

is there anything to do to change the title on apply button FilterListDelegate.show...

image
based on that pict, it's only available to change applybuttonstyle, how to change applybuttontitle ?

also

image
how to rename label search as an example I want to change from Search here.. to Maghanap dito..
image

thanks,

How to Add subtitle

**as the library support single item in choiceChipLabel **
how to add subtitle in choiceChipLabel if data has subtitle [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

Selected chip color

selectedTextBackgroundColor Feature unavailable in 0.0.8 update
How can change the selected chips color ??

Search filter doesn't work after empty list

Describe the bug
When you use the search textfield to filter the list, if you reach a dead end and your keyword doesn't correspond to items.
You then have to delete the whole keyword instead of just fixing your keyword typo in order to get the filter to work again.

for example:

List:

  • yorkshire
  • bulldog

if your keyword is "yorf": result is 0 items
then if you fix the keyword to "yor": result is still 0 items
until the you clear all the text and type "y": result 1 item

To Reproduce
Steps to reproduce the behavior:

Create a list and use search filters on it

Expected behavior
expected to have the keyword filter fire for each change in textfield

Select only one option [feature]

hey there ,
the package is all good , thanks for that,
i was hoping if you can add one more feature that would be great help
--------------The Feature----------------
the user can select the multiple options right
can you add something like the user can select only one option
when he tries to select other option then other option should be automatically deselected
---basically user can select only one option-------

Selected Text Count on bottom.

Is your feature request related to a problem? Please describe.
For me it is too much space, i would like the chips directly under the name and in the same time display how many are selected.

Make an option to display "selectedItemsCountOnBottom" boolean.

Screenshot 2022-12-05 at 10 19 18

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.