make search page type to search
This commit is contained in:
parent
1ebf6f32e0
commit
8b54b3ba1b
5 changed files with 103 additions and 1 deletions
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:frosty/apis/twitch_api.dart';
|
||||
import 'package:frosty/models/category.dart';
|
||||
|
|
@ -19,12 +21,17 @@ abstract class SearchStoreBase with Store {
|
|||
|
||||
final textFieldFocusNode = FocusNode();
|
||||
|
||||
Timer? _debounceTimer;
|
||||
|
||||
@readonly
|
||||
var _searchText = '';
|
||||
|
||||
@readonly
|
||||
var _searchHistory = ObservableList<String>();
|
||||
|
||||
@readonly
|
||||
var _isSearching = false;
|
||||
|
||||
@readonly
|
||||
ObservableFuture<List<ChannelQuery>>? _channelFuture;
|
||||
|
||||
|
|
@ -57,15 +64,48 @@ abstract class SearchStoreBase with Store {
|
|||
);
|
||||
}
|
||||
|
||||
/// Debounced handler for search-as-you-type.
|
||||
@action
|
||||
void onSearchTextChanged(String query) {
|
||||
_debounceTimer?.cancel();
|
||||
|
||||
if (query.isEmpty) {
|
||||
_isSearching = false;
|
||||
_channelFuture = null;
|
||||
_categoryFuture = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Show loading state immediately for responsive feedback.
|
||||
_isSearching = true;
|
||||
|
||||
_debounceTimer = Timer(const Duration(milliseconds: 300), () {
|
||||
runInAction(() => _performSearch(query));
|
||||
});
|
||||
}
|
||||
|
||||
/// Obtain the channels and categories that match the provided [query].
|
||||
/// Adds the query to search history.
|
||||
@action
|
||||
void handleQuery(String query) {
|
||||
if (query.isEmpty) return;
|
||||
|
||||
// Cancel any pending debounce since we're searching immediately.
|
||||
_debounceTimer?.cancel();
|
||||
|
||||
// Move the query to the most recent result (top of the stack).
|
||||
_searchHistory.remove(query);
|
||||
_searchHistory.insert(0, query);
|
||||
|
||||
_performSearch(query);
|
||||
}
|
||||
|
||||
/// Performs the actual search API calls.
|
||||
@action
|
||||
void _performSearch(String query) {
|
||||
// Futures are now pending, so isSearching can be cleared.
|
||||
_isSearching = false;
|
||||
|
||||
// Fetch the matching channels, sort it by live status, and then set it.
|
||||
_channelFuture = twitchApi.searchChannels(query: query).then((channels) {
|
||||
channels.sort((c1, c2) => c2.isLive ? 1 : -1);
|
||||
|
|
@ -96,6 +136,7 @@ abstract class SearchStoreBase with Store {
|
|||
}
|
||||
|
||||
void dispose() {
|
||||
_debounceTimer?.cancel();
|
||||
textEditingController.dispose();
|
||||
textFieldFocusNode.dispose();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue