part of '../widgets.dart'; /// ----------------------------------------------- /// [SearchView] class SearchView extends StatefulComponent { const SearchView({super.key}); @override State createState() => _SearchViewState(); } class _SearchViewState extends State { @override Widget build(BuildContext context) { return const Placeholder(); } } class LocalSearchView extends SearchView { final List list; final Widget Function(T) itemBuilder; final bool Function(T, String) filter; final Widget header; final List Function(String)? onSearch; LocalSearchView({ Key? key, required this.list, required this.itemBuilder, required this.filter, List Function(String)? onSearch, Widget? header, }) : header = header ?? const SizedBox.shrink(), onSearch = onSearch ?? ((String query) => list.where((documents) => filter(documents, query)).toList()), super(key: key); // return documents.where((documents) => filter(documents, query)).toList(); @override LocalSearchViewState createState() => LocalSearchViewState(); } class LocalSearchViewState extends State> { TextEditingController editingController = TextEditingController(); late List filteredItems; @override void initState() { filteredItems = widget.list; super.initState(); } @override Widget build(BuildContext context) { void filter(value) { safeSetState(() { filteredItems = widget.onSearch!(value); }); } return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.max, children: [ Expanded( child: ListView.builder( shrinkWrap: true, itemCount: filteredItems.length + 1, itemBuilder: (context, index) { if (index == 0) return widget.header; return widget.itemBuilder(filteredItems[index - 1]); }, ), ), Padding( padding: const EdgeInsets.all(30.0), child: TextField( onChanged: filter, controller: editingController, cursorColor: Colors.black, decoration: InputDecoration( prefixIcon: Icon(Icons.search), focusColor: Colors.black, hoverColor: Colors.black, fillColor: Colors.black, iconColor: Colors.black, contentPadding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0), border: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(15.0)), borderSide: BorderSide(color: Colors.black), // Set border color here ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(15.0)), borderSide: BorderSide( color: Colors.black), // Set focused border color here ), ), ), ), ], ); } } class RemoteSearchListView extends SearchView { final List list; final String title; final Widget Function(T) itemBuilder; // final Future> Function(String) fetchItems; final bool Function(T, String) filter; final Widget header; final List Function(String)? onSearch; RemoteSearchListView({ Key? key, // required this.fetchItems, required this.title, required this.list, required this.itemBuilder, required this.filter, List Function(String)? onSearch, Widget? header, }) : header = header ?? const SizedBox.shrink(), onSearch = onSearch ?? ((String query) => list.where((documents) => filter(documents, query)).toList()), super(key: key); @override _RemoteSearchViewState createState() => _RemoteSearchViewState(); } class _RemoteSearchViewState extends State> with Pageable { TextEditingController editingController = TextEditingController(); late List filteredItems; bool isLoading = false; final apiCall = FreAccessWSGlobal.getDocuments; int count = 0; final PagingController _pagingController = PagingController(firstPageKey: 1); @override void initState() { filteredItems = widget.list; _pagingController.addPageRequestListener( (dynamic pageKey) => fetchPage( dataProvider: () async { final newItems = await apiCall.call(pageKey.toString()); if (newItems.jsonBody == null) return (false, null); final List docs = (newItems.jsonBody['value']['list'] as List?) ?? []; _pagingController.nextPageKey = pageKey + 1; safeSetState(() { count = newItems.jsonBody['value']['count'] ?? 0; }); return (docs.isNotEmpty, docs); }, onDataUnavailable: () { setState(() {}); showNoMoreDataSnackBar(context); }, onDataAvailable: (vehicles) { setState(() {}); _pagingController.appendLastPage(vehicles); }, onFetchError: (e, s) { DialogUtil.errorDefault(context); LogUtil.requestAPIFailed( "proccessRequest.php", "", "Consulta de Veículo", e, s); setState(() {}); }, ), ); _pagingController.addStatusListener(_showError); super.initState(); } Future _showError(PagingStatus status) async { if (status == PagingStatus.subsequentPageError) { final message = FFLocalizations.of(context).getVariableText( enText: 'Something went wrong while fetching a new page.', ptText: 'Algo deu errado ao buscar uma nova página.', ); final retry = FFLocalizations.of(context).getVariableText( enText: 'Retry', ptText: 'Recarregar', ); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), action: SnackBarAction( label: retry, onPressed: () => _pagingController.retryLastFailedRequest(), ), ), ); } } void filterSearchResults(String query) async { setState(() { isLoading = true; }); // final results = await widget.fetchItems(query); // setState(() { // filteredItems = results; // isLoading = false; // }); } @override Widget build(BuildContext context) { final noDataFound = FFLocalizations.of(context).getVariableText( ptText: "Nenhum veículo encontrado!", enText: "No vehicle found", ); return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.max, children: [ Padding( padding: const EdgeInsets.all(8.0), child: TextField( onChanged: (value) => filterSearchResults(value), controller: editingController, decoration: InputDecoration( labelText: "Search", hintText: "Search", prefixIcon: Icon(Icons.search), border: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(25.0)), ), ), ), ), widget.header, buildPaginatedListView( noDataFound, _pagingController, (BuildContext context, dynamic item, int index) => widget.itemBuilder(item), ), ], ); } }