blob: ecd33b9772e0689e9d4c7433f25667fc44728e74 [file] [log] [blame]
import 'package:flutter/material.dart';
import 'package:github_search/empty_result_widget.dart';
import 'package:github_search/github_api.dart';
import 'package:github_search/search_bloc.dart';
import 'package:github_search/search_error_widget.dart';
import 'package:github_search/search_intro_widget.dart';
import 'package:github_search/search_loading_widget.dart';
import 'package:github_search/search_result_widget.dart';
import 'package:github_search/search_state.dart';
// The View in a Stream-based architecture takes two arguments: The State Stream
// and the onTextChanged callback. In our case, the onTextChanged callback will
// emit the latest String to a Stream<String> whenever it is called.
//
// The State will use the Stream<String> to send new search requests to the
// GithubApi.
class SearchScreen extends StatefulWidget {
final GithubApi api;
SearchScreen({Key key, GithubApi api})
: this.api = api ?? GithubApi(),
super(key: key);
@override
SearchScreenState createState() {
return SearchScreenState();
}
}
class SearchScreenState extends State<SearchScreen> {
SearchBloc bloc;
@override
void initState() {
super.initState();
bloc = SearchBloc(widget.api);
}
@override
void dispose() {
bloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return StreamBuilder<SearchState>(
stream: bloc.state,
initialData: SearchNoTerm(),
builder: (BuildContext context, AsyncSnapshot<SearchState> snapshot) {
final state = snapshot.data;
return Scaffold(
body: Stack(
children: <Widget>[
Flex(direction: Axis.vertical, children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(16.0, 24.0, 16.0, 4.0),
child: TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Search Github...',
),
style: TextStyle(
fontSize: 36.0,
fontFamily: "Hind",
decoration: TextDecoration.none,
),
onChanged: bloc.onTextChanged.add,
),
),
Expanded(
child: Stack(
children: <Widget>[
// Fade in an intro screen if no term has been entered
SearchIntro(visible: state is SearchNoTerm),
// Fade in an Empty Result screen if the search contained
// no items
EmptyWidget(visible: state is SearchEmpty),
// Fade in a loading screen when results are being fetched
// from Github
LoadingWidget(visible: state is SearchLoading),
// Fade in an error if something went wrong when fetching
// the results
SearchErrorWidget(visible: state is SearchError),
// Fade in the Result if available
SearchResultWidget(
items:
state is SearchPopulated ? state.result.items : [],
),
],
),
)
])
],
),
);
},
);
}
}