fix: accurate loading indicator for search, add button to clear search

main
daniel-michel 2024-01-09 12:47:42 +01:00
parent d5861bdb78
commit a0e4edb508
3 changed files with 43 additions and 21 deletions

View File

@ -41,6 +41,7 @@ class _HomePageState extends State<HomePage>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late LiveSearch liveSearch;
late TextEditingController _searchController;
@override
void initState() {
@ -49,12 +50,14 @@ class _HomePageState extends State<HomePage>
vsync: this, // the SingleTickerProviderStateMixin
duration: const Duration(milliseconds: 300),
);
_searchController = TextEditingController();
liveSearch = LiveSearch(widget.manager);
}
@override
void dispose() {
_controller.dispose();
_searchController.dispose();
super.dispose();
}
@ -62,21 +65,42 @@ class _HomePageState extends State<HomePage>
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: TextField(
decoration: const InputDecoration(
hintText: "Search",
border: InputBorder.none,
),
onChanged: (value) {
setState(() {
if (value.isEmpty) {
_controller.reverse();
} else {
_controller.forward();
}
liveSearch.updateSearch(value);
});
},
title: Row(
children: [
Expanded(
child: TextField(
controller: _searchController,
decoration: const InputDecoration(
hintText: "Search",
border: InputBorder.none,
),
onChanged: (value) {
setState(() {
if (value.isEmpty) {
_controller.reverse();
} else {
_controller.forward();
}
liveSearch.updateSearch(value);
});
},
),
),
AnimatedBuilder(
animation: _controller,
builder: (context, child) {
if (liveSearch.searchTerm.isEmpty) return Container();
return IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
_searchController.clear();
liveSearch.updateSearch("");
_controller.reverse();
},
);
},
),
],
),
actions: [HamburgerMenu(widget.manager)],
),

View File

@ -7,6 +7,8 @@ class DelayedFunctionCaller {
DelayedFunctionCaller(this.function, this.duration);
get scheduled => _timer != null && _timer!.isActive;
void call() {
// If a timer is already active, return.
if (_timer != null && _timer!.isActive) {

View File

@ -9,32 +9,29 @@ class LiveSearch extends ChangeNotifier {
Duration minTimeBetweenRequests = const Duration(milliseconds: 200);
late final DelayedFunctionCaller _searchCaller;
final MovieManager manager;
bool loading = false;
bool searchingOnline = false;
LiveSearch(this.manager) {
_searchCaller = DelayedFunctionCaller(searchOnline, minTimeBetweenRequests);
}
get loading => searchingOnline || _searchCaller.scheduled;
void updateSearch(String search) {
searchTerm = search;
if (searchTerm.isEmpty) {
return;
}
searchResults = manager.localSearch(search);
loading = true;
_searchCaller.call();
notifyListeners();
}
void searchOnline() async {
if (searchTerm.isEmpty) {
loading = false;
notifyListeners();
return;
}
if (searchingOnline) {
loading = true;
_searchCaller.call();
notifyListeners();
return;
@ -55,7 +52,6 @@ class LiveSearch extends ChangeNotifier {
notifyListeners();
} finally {
searchingOnline = false;
loading = false;
notifyListeners();
}
}