Modified the search functionality so teh resulting list updates
as the user types. Added a clearing button to the search box.
This commit is contained in:
parent
d59e7368c5
commit
47c7c4cef9
2 changed files with 95 additions and 43 deletions
|
|
@ -25,14 +25,27 @@ class HomeBloc {
|
|||
/// A subject of list of task model.
|
||||
final _tasks = BehaviorSubject<List<TaskModel>>();
|
||||
|
||||
/// Current text from the search box.
|
||||
String _searchBoxText = '';
|
||||
/// A subject of the search box updates.
|
||||
final _searchBoxText = BehaviorSubject<String>(seedValue: '');
|
||||
|
||||
// Stream getters.
|
||||
|
||||
// The result has to be a combination of the tasks streams and the text
|
||||
// stream, because otherwise, the tasks stream has no way of knowing when
|
||||
// there's a new update in the text.
|
||||
//
|
||||
// The search box transformation has to be applied after the combination,
|
||||
// otherwhise the value used for filtering is outdated and the list output is
|
||||
// not synchronized with the current value of the searhc box text.
|
||||
/// An observalbe of the taks of a user.
|
||||
Observable<List<TaskModel>> get userTasks => _tasks.stream
|
||||
.transform(prioritySortTransformer())
|
||||
.transform(searchBoxTransformer());
|
||||
Observable<List<TaskModel>> get userTasks =>
|
||||
Observable.combineLatest2<String, List<TaskModel>, List<TaskModel>>(
|
||||
_searchBoxText.stream,
|
||||
_tasks.stream.transform(prioritySortTransformer()),
|
||||
(text, tasks) {
|
||||
return tasks;
|
||||
},
|
||||
).transform(searchBoxTransformer());
|
||||
|
||||
/// An observable of the current logged in user.
|
||||
Observable<FirebaseUser> get userStream => _auth.userStream;
|
||||
|
|
@ -55,17 +68,17 @@ class HomeBloc {
|
|||
sink.add(
|
||||
taskList.where(
|
||||
(TaskModel task) {
|
||||
if (_searchBoxText == '') {
|
||||
if (_searchBoxText.value == '') {
|
||||
return true;
|
||||
}
|
||||
// Return true if the text in the search box matches the title
|
||||
// or the text of the task.
|
||||
return task.event
|
||||
.toLowerCase()
|
||||
.contains(_searchBoxText.toLowerCase()) ||
|
||||
.contains(_searchBoxText.value.toLowerCase()) ||
|
||||
task.text
|
||||
.toLowerCase()
|
||||
.contains(_searchBoxText.toLowerCase());
|
||||
.contains(_searchBoxText.value.toLowerCase());
|
||||
},
|
||||
).toList(),
|
||||
);
|
||||
|
|
@ -106,10 +119,11 @@ class HomeBloc {
|
|||
|
||||
/// Updates the serach box text.
|
||||
void updateSearchBoxText(String newText) {
|
||||
_searchBoxText = newText;
|
||||
_searchBoxText.add(newText);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_searchBoxText.close();
|
||||
_tasks.close();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,27 +6,87 @@ import './gradient_touchable_container.dart';
|
|||
//TODO: Add neccessary properties to be able to inform of changes in text field.
|
||||
|
||||
/// A search box that mathces the app mocks.
|
||||
class SearchBox extends StatelessWidget {
|
||||
class SearchBox extends StatefulWidget {
|
||||
/// Height of the sarch box.
|
||||
final double height;
|
||||
|
||||
/// Function to be called when the text changes.
|
||||
final Function(String) onChanged;
|
||||
|
||||
/// Creates a search box.
|
||||
///
|
||||
/// the height should be equal or larger than 50.
|
||||
SearchBox({
|
||||
@required this.height,
|
||||
@required this.onChanged,
|
||||
}) : assert(height >= 50);
|
||||
|
||||
@override
|
||||
_SearchBoxState createState() => _SearchBoxState();
|
||||
}
|
||||
|
||||
class _SearchBoxState extends State<SearchBox> {
|
||||
/// Controller for the [TextFiel].
|
||||
final TextEditingController _controller = TextEditingController();
|
||||
|
||||
initState() {
|
||||
_controller.addListener(() => widget.onChanged(_controller.text));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> containerRowChildren = <Widget>[
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Icon(
|
||||
FontAwesomeIcons.sistrix,
|
||||
color: Colors.white,
|
||||
),
|
||||
SizedBox(
|
||||
width: 8,
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _controller,
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
hintText: 'Search...',
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
cursorColor: Colors.white,
|
||||
scrollPadding: EdgeInsets.zero,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
if (_controller.text != '') {
|
||||
containerRowChildren.add(
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
FontAwesomeIcons.timesCircle,
|
||||
color: Colors.white,
|
||||
),
|
||||
onPressed: onClearButtonPressed,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Row(
|
||||
children: <Widget>[
|
||||
Spacer(flex: 1),
|
||||
Expanded(
|
||||
flex: 8,
|
||||
child: GradientTouchableContainer(
|
||||
radius: height / 2,
|
||||
height: height,
|
||||
radius: widget.height / 2,
|
||||
height: widget.height,
|
||||
shadow: BoxShadow(
|
||||
color: Color(0x20FFFFFF),
|
||||
offset: Offset(0, 3),
|
||||
|
|
@ -34,37 +94,7 @@ class SearchBox extends StatelessWidget {
|
|||
spreadRadius: 1,
|
||||
),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Icon(
|
||||
FontAwesomeIcons.sistrix,
|
||||
color: Colors.white,
|
||||
),
|
||||
SizedBox(
|
||||
width: 8,
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
onChanged: onChanged,
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
hintText: 'Search...',
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
cursorColor: Colors.white,
|
||||
scrollPadding: EdgeInsets.zero,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
children: containerRowChildren,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -72,4 +102,12 @@ class SearchBox extends StatelessWidget {
|
|||
],
|
||||
);
|
||||
}
|
||||
|
||||
void onClearButtonPressed() {
|
||||
_controller.text = '';
|
||||
// The controller does not notify its listeners when the text is set
|
||||
// explicitely. We have to do it manually.
|
||||
widget.onChanged(_controller.text);
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue