258 lines
7.6 KiB
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),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|