flutter-freaccess-hub/lib/shared/widgets/view/search_view.dart

258 lines
7.6 KiB
Dart

part of '../widgets.dart';
/// -----------------------------------------------
/// [SearchView]
class SearchView<T> extends StatefulComponent {
const SearchView({super.key});
@override
State<SearchView> createState() => _SearchViewState();
}
class _SearchViewState<T> extends State<SearchView> {
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}
class LocalSearchView<T> extends SearchView<T> {
final List<T> list;
final Widget Function(T) itemBuilder;
final bool Function(T, String) filter;
final Widget header;
final List<T> Function(String)? onSearch;
LocalSearchView({
Key? key,
required this.list,
required this.itemBuilder,
required this.filter,
List<T> 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<T> createState() => LocalSearchViewState<T>();
}
class LocalSearchViewState<T> extends State<LocalSearchView<T>> {
TextEditingController editingController = TextEditingController();
late List<T> 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: <Widget>[
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<T> extends SearchView<T> {
final List<T> list;
final String title;
final Widget Function(T) itemBuilder;
// final Future<List<T>> Function(String) fetchItems;
final bool Function(T, String) filter;
final Widget header;
final List<T> Function(String)? onSearch;
RemoteSearchListView({
Key? key,
// required this.fetchItems,
required this.title,
required this.list,
required this.itemBuilder,
required this.filter,
List<T> 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<T> createState() => _RemoteSearchViewState<T>();
}
class _RemoteSearchViewState<T> extends State<RemoteSearchListView<T>>
with Pageable {
TextEditingController editingController = TextEditingController();
late List<T> filteredItems;
bool isLoading = false;
final apiCall = FreAccessWSGlobal.getDocuments;
int count = 0;
final PagingController<int, dynamic> _pagingController =
PagingController<int, dynamic>(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<dynamic> docs =
(newItems.jsonBody['value']['list'] as List<dynamic>?) ?? [];
_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<void> _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: <Widget>[
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<int, dynamic>(
noDataFound,
_pagingController,
(BuildContext context, dynamic item, int index) =>
widget.itemBuilder(item),
),
],
);
}
}