fix: accurate loading indicator for search, add button to clear search
parent
d5861bdb78
commit
a0e4edb508
|
@ -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)],
|
||||
),
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue