/// Result from a data source fetch operation. class DataGridResult { const DataGridResult({ required this.items, required this.totalCount, this.hasMore = false, }); /// The fetched items. final List items; /// Total count of items (for pagination display). final int totalCount; /// Whether there are more items to load (for infinite scroll). final bool hasMore; /// Creates an empty result. const DataGridResult.empty() : items = const [], totalCount = 0, hasMore = false; } /// Abstract data source for DataGrid. /// /// Implement this to provide data to the grid. Can be backed by /// API calls, local database, or in-memory lists. abstract class DataGridSource { /// Fetches items from the data source. /// /// - [searchQuery]: Optional search text to filter results. /// - [sortField]: Field name to sort by. /// - [sortDescending]: Whether to sort in descending order. /// - [offset]: Number of items to skip (for pagination). /// - [limit]: Maximum number of items to return. Future> fetch({ String? searchQuery, String? sortField, bool sortDescending = false, int? offset, int? limit, }); /// Gets the total count of items matching the query. /// /// Override this if you need a separate count query. /// By default, returns the totalCount from the last fetch. Future count({String? searchQuery}) async { final result = await fetch(searchQuery: searchQuery, limit: 0); return result.totalCount; } } /// In-memory data source for local data. class InMemoryDataSource extends DataGridSource { InMemoryDataSource({ required this.items, this.searchMatcher, this.sortComparator, }); /// All items in the data source. final List items; /// Function to check if an item matches the search query. final bool Function(T item, String query)? searchMatcher; /// Function to compare two items for sorting. final int Function(T a, T b, String field, bool descending)? sortComparator; @override Future> fetch({ String? searchQuery, String? sortField, bool sortDescending = false, int? offset, int? limit, }) async { var result = List.from(items); // Apply search filter if (searchQuery != null && searchQuery.isNotEmpty && searchMatcher != null) { result = result.where((item) => searchMatcher!(item, searchQuery)).toList(); } // Apply sorting if (sortField != null && sortComparator != null) { result.sort((a, b) => sortComparator!(a, b, sortField, sortDescending)); } final totalCount = result.length; // Apply pagination if (offset != null && offset > 0) { result = result.skip(offset).toList(); } if (limit != null && limit > 0) { result = result.take(limit).toList(); } return DataGridResult( items: result, totalCount: totalCount, hasMore: offset != null && limit != null && (offset + limit) < totalCount, ); } }