Advertisement
chayanforyou

flutter_paging_viewmodel_example_1

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