chayanforyou

flutter_paging_viewmodel_example_1

Jun 19th, 2025 (edited)
1,554
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Dart 8.58 KB | None | 0 0
  1. class LocationViewModel extends StateNotifier<AsyncValue<List<Destination>>> {
  2.   final List<Destination> initialLocations;
  3.   final String employeeId;
  4.   final int year;
  5.   final int month;
  6.   final int day;
  7.   final String shift;
  8.  
  9.   LocationViewModel({
  10.     required this.initialLocations,
  11.     required this.employeeId,
  12.     required this.year,
  13.     required this.month,
  14.     required this.day,
  15.     required this.shift,
  16.   }) : super(const AsyncValue.loading()) {
  17.     _fetchLocations();
  18.   }
  19.  
  20.   String _searchTerm = '';
  21.   List<Destination> _locations = [];
  22.  
  23.   // Getter for the selected locations
  24.   List<Destination> get selectedLocations => initialLocations;
  25.  
  26.   // Method to fetch locations
  27.   Future<void> _fetchLocations() async {
  28.     try {
  29.       state = const AsyncValue.loading();
  30.       final response = await TourPlanRepository.instance.getTourPlanLocation(employeeId, year, month, day, shift);
  31.       final locations = response.data ?? [];
  32.       _locations = locations
  33.           .map((destination) => destination.copyWith(
  34.         selected: initialLocations.any((des) => des.placeKey == destination.placeKey),
  35.       )).toList();
  36.  
  37.       state = AsyncValue.data(_locations);
  38.     } catch (e, stackTrace) {
  39.       state = AsyncValue.error(e, stackTrace);
  40.     }
  41.   }
  42.  
  43.   // Method to update the search term
  44.   void updateSearchTerm(String term) {
  45.     _searchTerm = term.trim();
  46.     state = AsyncValue.data(_filterLocations());
  47.   }
  48.  
  49.   // Method to toggle the selection of a location
  50.   void toggleSelection(Destination location) {
  51.     final index = _locations.indexWhere((des) => des.placeKey == location.placeKey);
  52.     if (index != -1) {
  53.       final isSelected = _locations[index].selected;
  54.       // Update the main list
  55.       _locations[index] = _locations[index].copyWith(selected: !isSelected);
  56.  
  57.       // Update the selected list
  58.       if (isSelected) {
  59.         initialLocations.removeWhere((des) => des.placeKey == location.placeKey);
  60.       } else {
  61.         initialLocations.add(_locations[index]);
  62.       }
  63.  
  64.       // Update state without resetting the filtered list
  65.       state = AsyncValue.data(_filterLocations());
  66.     }
  67.   }
  68.  
  69.  
  70.   // Method to filter locations based on search term
  71.   List<Destination> _filterLocations() {
  72.     return _locations.where((des) {
  73.       return des.place?.name?.toLowerCase().contains(_searchTerm.toLowerCase()) ?? false;
  74.     }).toList();
  75.   }
  76. }
  77.  
  78. final locationViewModelProvider =
  79.     StateNotifierProvider.family.autoDispose<LocationViewModel, AsyncValue<List<Destination>>, LocationQueryParams>(
  80.   (ref, params) => LocationViewModel(
  81.     initialLocations: params.initialLocations,
  82.     employeeId: params.employeeId,
  83.     year: params.year,
  84.     month: params.month,
  85.     day: params.day,
  86.     shift: params.shift,
  87.   ),
  88. );
  89.  
  90. // --------------------------------------------------
  91.  
  92. class LocationViewModel extends StateNotifier<PagingState<int, Destination>> {
  93.   final String employeeId;
  94.   final int year;
  95.   final int month;
  96.   final int day;
  97.   final String shift;
  98.  
  99.   final Debouncer _debounce = Debouncer();
  100.  
  101.   late final List<Destination> _selectedLocations;
  102.  
  103.   Set<String?> get _selectedKeys =>
  104.       _selectedLocations.map((e) => e.placeKey).toSet();
  105.  
  106.   String? _searchTerm;
  107.  
  108.   LocationViewModel({
  109.     required List<Destination> initialLocations,
  110.     required this.employeeId,
  111.     required this.year,
  112.     required this.month,
  113.     required this.day,
  114.     required this.shift,
  115.   }) : super(PagingState()) {
  116.     _selectedLocations = List.from(initialLocations);
  117.   }
  118.  
  119.   List<Destination> get selectedLocations => _selectedLocations;
  120.  
  121.   /// Fetches the next page of data
  122.   Future<void> fetchNextPage() async {
  123.     if (state.isLoading) return;
  124.  
  125.     state = state.copyWith(isLoading: true, error: null);
  126.  
  127.     try {
  128.       final newKey = state.keys?.last == null ? 0 : state.keys!.last + 1;
  129.       final response = await TourPlanRepository.instance.getTourPlanLocation(
  130.         employeeId,
  131.         year,
  132.         month,
  133.         day,
  134.         shift,
  135.         _searchTerm,
  136.         newKey,
  137.       );
  138.       final locations = response.data?.content ?? [];
  139.  
  140.       final newItems = locations.map((location) {
  141.         return location.copyWith(
  142.           selected: _selectedKeys.contains(location.placeKey),
  143.         );
  144.       }).toList();
  145.  
  146.       state = state.copyWith(
  147.         pages: [...?state.pages, newItems],
  148.         keys: [...?state.keys, newKey],
  149.         hasNextPage: response.data?.hasNext,
  150.         isLoading: false,
  151.       );
  152.     } catch (error) {
  153.       state = state.copyWith(error: error, isLoading: false);
  154.     }
  155.   }
  156.  
  157.   /// Updates search term and refreshes the list
  158.   void updateSearchTerm(String searchTerm) {
  159.     _searchTerm = searchTerm;
  160.     _debounce.run(refreshList);
  161.   }
  162.  
  163.   /// Clear search and refreshes the list
  164.   void clearSearchTerm() {
  165.     _searchTerm = null;
  166.     _debounce.run(refreshList);
  167.   }
  168.  
  169.   /// Refreshes the list and fetches the first page
  170.   void refreshList() {
  171.     state = PagingState();
  172.     fetchNextPage();
  173.   }
  174.  
  175.   /// Method to toggle the selection of a location
  176.   void toggleSelection(Destination destination) {
  177.     final isSelected = !destination.selected;
  178.  
  179.     final updatedPages = state.pages?.map((page) {
  180.       return page.map((loc) {
  181.         if (loc.placeKey == destination.placeKey) {
  182.           return loc.copyWith(selected: isSelected);
  183.         }
  184.         return loc;
  185.       }).toList();
  186.     }).toList();
  187.  
  188.     state = state.copyWith(pages: updatedPages);
  189.  
  190.     // Update internal selected list
  191.     if (isSelected) {
  192.       _selectedLocations.add(destination.copyWith(selected: true));
  193.     } else {
  194.       _selectedLocations.removeWhere((e) => e.placeKey == destination.placeKey);
  195.     }
  196.   }
  197. }
  198.  
  199. final locationViewModelProvider = StateNotifierProvider.family
  200.     .autoDispose<
  201.       LocationViewModel,
  202.       PagingState<int, Destination>,
  203.       LocationQueryParams
  204.     >(
  205.       (ref, params) => LocationViewModel(
  206.         initialLocations: params.initialLocations,
  207.         employeeId: params.employeeId,
  208.         year: params.year,
  209.         month: params.month,
  210.         day: params.day,
  211.         shift: params.shift,
  212.       ),
  213.     );
  214.  
  215.  
  216. // --------------------------------------------------
  217.  
  218. class LocationViewModel extends StateNotifier<AsyncValue<List<Places>>> {
  219.   final List<Places> initialLocations;
  220.   final String employeeId;
  221.   final int year;
  222.   final int month;
  223.   final Debouncer _debounce = Debouncer();
  224.   String _searchTerm = '';
  225.  
  226.   LocationViewModel({
  227.     required this.initialLocations,
  228.     required this.employeeId,
  229.     required this.year,
  230.     required this.month,
  231.   }) : super(const AsyncValue.loading()) {
  232.     _fetchLocations();
  233.   }
  234.  
  235.   String get searchTerm => _searchTerm;
  236.  
  237.   // Method to fetch locations from the API based on the search term
  238.   Future<void> _fetchLocations() async {
  239.     try {
  240.       state = const AsyncValue.loading();
  241.       final response = await TourPlanRepository.instance.getTourPlanLocation(employeeId, year, month);
  242.       final locations = response.data ?? [];
  243.  
  244.       // Update the state with the new list of places
  245.       state = AsyncValue.data(
  246.         locations.map((location) {
  247.           return location.copyWith(
  248.             selected: initialLocations.any((loc) => loc.id == location.id),
  249.           );
  250.         }).toList(),
  251.       );
  252.     } catch (e, stackTrace) {
  253.       state = AsyncValue.error(e, stackTrace);
  254.     }
  255.   }
  256.  
  257.   // Method to update the search term with debounce
  258.   void updateSearchTerm(String term) {
  259.     _searchTerm = term.trim();
  260.  
  261.     _debounce.run(() {
  262.       _fetchLocations();
  263.     });
  264.   }
  265.  
  266.   // Method to toggle the selection of a location
  267.   void toggleSelection(Places location) {
  268.     final locations = state.value ?? [];
  269.  
  270.     final index = locations.indexWhere((l) => l.id == location.id);
  271.     if (index == -1) return;
  272.  
  273.     final isSelected = locations[index].selected;
  274.     final updatedLocation = locations[index].copyWith(selected: !isSelected);
  275.  
  276.     locations[index] = updatedLocation;
  277.  
  278.     state = AsyncValue.data(locations);
  279.  
  280.     if (isSelected) {
  281.       initialLocations.removeWhere((l) => l.id == location.id);
  282.     } else {
  283.       initialLocations.add(updatedLocation);
  284.     }
  285.   }
  286.  
  287.   // Getter for the selected locations
  288.   List<Places> get selectedLocations => initialLocations;
  289. }
  290.  
  291. final locationViewModelProvider =
  292.     StateNotifierProvider.family.autoDispose<LocationViewModel, AsyncValue<List<Places>>, LocationQueryParams>(
  293.   (ref, params) => LocationViewModel(
  294.     initialLocations: params.initialLocations,
  295.     employeeId: params.employeeId,
  296.     year: params.year,
  297.     month: params.month,
  298.   ),
  299. );
  300.  
Advertisement
Add Comment
Please, Sign In to add comment