i am trying to implement login functionality using bloc pattern in flutter. So I want to navigate to main page after authentication is successful. from loginBloc.dart I will get the status inside the streamBuilder in login.dart when the status is success I want to navigate to main.dart but I cant able to understand how to call the main.dart inside the streamBuilder in login.dart.
login.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_svg/svg.dart';
import 'package:hotelorders/bloc/LoginBloc.dart';
import 'package:hotelorders/screens/Home.dart';
class Login extends StatefulWidget
{
#override
State<StatefulWidget> createState() {
return LoginState();
}
}
class LoginState extends State<Login>
{
final LoginBloc _loginBloc = LoginBloc();
String _email,_password;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
#override
void dispose()
{
_loginBloc.dispose();
super.dispose();
}
Widget _progressBar()
{
return StreamBuilder<bool>(
stream: _loginBloc.progressStream,
builder: (BuildContext context,AsyncSnapshot<bool> snapShot) {
bool visible;
if(snapShot.data == null)
{
visible = false;
}
else
{
visible = snapShot.data;
}
return Visibility(
maintainSize: true,
maintainAnimation: true,
maintainState: true,
visible: visible,
child: Container(
child: Center(
child: SizedBox(
width: 60,
height: 60,
child: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey,
offset: Offset(0.0, 1.0), //(x,y)
blurRadius: 1.0,
),
],
),
),
Center(
child: CircularProgressIndicator(),
)
],
),
)
)
),
);
}
);
}
Widget _emailTextField()
{
return TextFormField(
decoration: InputDecoration(
labelText: "Email id",
border: OutlineInputBorder(
borderRadius: new BorderRadius.circular(32.0),
)
),
keyboardType: TextInputType.emailAddress,
validator: (String value){
if(value.isEmpty || !RegExp(r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?").hasMatch(value))
{
return "Enter a valid email id";
}
return null;
},
onSaved: (String value){
_email = value;
},
);
}
Widget _passwordTextField()
{
return TextFormField(
decoration: InputDecoration(labelText: "Password",
filled: true,
border: OutlineInputBorder(
borderRadius: new BorderRadius.circular(32.0),
),
fillColor: Colors.white
),
keyboardType: TextInputType.text,
obscureText: true,
validator: (String value){
if(value.isEmpty)
{
return "Enter a valid password";
}
else if(value.length < 8)
{
return "Password is too short";
}
else
{
return null;
}
},
);
}
void _login()
{
if(!_formKey.currentState.validate())
{
return;
}
_formKey.currentState.save();
Map<String,String> map = new Map();
map['email'] = _email;
map['password'] = _password;
_loginBloc.login(map);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
Container(
alignment: Alignment.center,
margin: EdgeInsets.fromLTRB(0, 48, 0, 0),
child: Text(
"Take Orders and",
style: TextStyle(color: Theme.of(context).primaryColorDark,fontSize: 20),
),
),
Container(
child: Text(
"Track the Best Selling Items",
style: TextStyle(color: Theme.of(context).primaryColor,fontSize: 16),
),
),
Container(
margin: EdgeInsets.fromLTRB(16, 0, 16, 0),
child: SvgPicture.asset('assets/images/undraw_booking.svg',width: 100.0,height: 280.0,),
),
Container(
margin: EdgeInsets.fromLTRB(16, 0, 0, 0),
child:Row(
children: <Widget>[
Text(
"Login To ",
style: TextStyle(color: Colors.black,fontSize: 20)
),
Text(
"Take orders",
style: TextStyle(color: Theme.of(context).primaryColorDark,fontSize: 20),
)
],
),
),
Container(
margin: EdgeInsets.fromLTRB(16, 8, 16, 0),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.fromLTRB(0, 8, 0, 0),
child: _emailTextField(),
),
Container(
margin: EdgeInsets.fromLTRB(0, 8, 0, 0),
child: _passwordTextField(),
),
Container(
margin: EdgeInsets.fromLTRB(0, 8, 0, 0),
child: Align(
alignment: Alignment.centerLeft,
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32.0)
),
padding: EdgeInsets.fromLTRB(64, 12, 64, 12),
color: Theme.of(context).accentColor,
textColor: Colors.white,
child: Text(
"Login",
),
onPressed: (){
_login();
},
) ,
),
),
StreamBuilder<dynamic>(
stream:_loginBloc.loginStateStream,
builder: (BuildContext context, AsyncSnapshot<dynamic> snapShot){
if(snapShot.data == "success")
{
// WidgetsBinding.instance.addPostFrameCallback((_){
// Navigator.push(context, MaterialPageRoute(
// builder: (context)=> Home()
// ));
// });
}
else if(snapShot.data != null && snapShot.data != "success")
{
WidgetsBinding.instance.addPostFrameCallback((_) {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text('${snapShot.data}',
style: TextStyle(color: Colors.black),),
backgroundColor: Color(0xFFe5e5e5),
));
// showDialog(context: context,builder: (BuildContext con){
// return AlertDialog(
// title: Text('${snapShot.data}'),
// );
// });
});
}
return Container();
},
)
],
),
),
)
],
),
)
),
_progressBar(),
],
),
);
}
}
LoginBloc.dart
import 'dart:async';
class LoginBloc
{
// here event comes in and state goes out
//stream conntroller for output
final _loginStateController = StreamController<String>();
//stream controller for input
final _loginEventController = StreamController<Map<String,String>>();
final _progressController = StreamController<bool>();
StreamSink<String> get loginStateSink => _loginStateController.sink;
Stream<String> get loginStateStream => _loginStateController.stream;
Sink<Map<String,String>> get loginEventSink => _loginEventController.sink;
Stream<bool> get progressStream => _progressController.stream;
StreamSink<bool> get progressSink => _progressController.sink;
LoginBloc()
{
progressSink.add(false);
_loginEventController.stream.listen(login);
}
login(Map<String,String> loginDetails)
{
progressSink.add(true);
Timer(Duration(seconds: 3), () {
progressSink.add(false);
loginStateSink.add("success");
});
// when we pass data in sink we get the output from stream
}
void dispose()
{
_loginEventController.close();
_loginStateController.close();
_progressController.close();
}
}
You are almost there. The following should work :
if(snapShot.data == "success")
{
Navigator.push(
context, MaterialPageRoute(builder: (context)=> Home()));
}
Note : WidgetsBinding.instance.addPostFrameCallback is used to get a callback when widget tree is loaded.
Related
I have been able to display Json data from API in FutureBuilder Widget. However, the widget has checkbox for each list. Whenever I check on one list, the whole list get checked.
I want a help on how to check each list individually and be able to use the data of the selected list.
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:bottom_navy_bar/bottom_navy_bar.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mar/Components/mydrawer.dart';
import 'package:mar/Services/auth.dart';
import 'package:mar/sccreens/readRequirements.dart';
import 'package:mar/sccreens/scanAnalysis.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../constants.dart';
import 'infoAnalysis.dart';
import 'login_screen.dart';
class Know extends StatefulWidget {
static String id = 'Know';
#override
_KnowState createState() => _KnowState();
}
class _KnowState extends State<Know> {
List sympotms = [];
int currentIndex = 2;
bool valuefirst = false;
int _bottomBarIndex = 0;
Auth _auth;
showdialogall(context, String mytitle, String mycontent) {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
title: Text(
mytitle,
style: TextStyle(color: Colors.deepOrange),
),
content: Text(mycontent),
actions: [
Center(
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
color: kMainColor,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ReadReq()),
);
},
child: Text(
"Requirements",
style: TextStyle(color: Colors.black),
)),
),
],
);
});
}
Future fetchdata() async {
var res = await http.get("http://10.0.2.2/medical/symptoms.php");
if (res.statusCode == 200) {
var obj = json.decode(res.body);
return obj;
}
}
bool isSearching = false;
#override
void initState() {
fetchdata().then((data) {
setState(() {
sympotms = data;
});
});
super.initState();
}
void _filterSymptoms(value) {
setState(() {
filteredsympotms = sympotms
.where(
(sym) => sym['name'].toLowerCase().contains(value.toLowerCase()))
.toList();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: kMainColor,
title: Text(
"Know Your Analysis",
style: TextStyle(
fontFamily: 'Pacifico',
),
),
actions: <Widget>[
FlatButton(
child: CircleAvatar(
child: Image(
image: AssetImage('images/icons/medical.png'),
),
backgroundColor: Colors.black,
),
onPressed: () {
Navigator.pushNamed(context, Scan.id);
},
),
],
centerTitle: true,
),
drawer: MyDrawer(),
body: Column(
children: [
Expanded(
child: sympotms.length > 0
? ListView.builder(
itemBuilder: (_, index) {
return Container(
child: Row(
children: [
SizedBox(width: 10),
Checkbox(
value: this.valuefirst,
onChanged: (bool value) {
setState(() {
valuefirst = value;
});
},
checkColor: Colors.greenAccent,
activeColor: Colors.black,
),
Text(
"${sympotms[index]['SymptomsName']}",
style: TextStyle(fontSize: 17.0),
),
],
),
);
},
itemCount: sympotms.length,
)
: Container(child: Center(child: Text("Loading..."))),
),
RaisedButton(
child: Text(
" Submit ",
style: TextStyle(fontSize: 20),
),
onPressed: () {
showdialogall(context, "Result !", "CBC Test");
},
// onPressed: showdialogall(context, "Result !", "CBC Test"),
color: Colors.green,
textColor: Colors.white,
splashColor: Colors.grey,
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
),
],
),
//Navigation
bottomNavigationBar: BottomNavyBar(
animationDuration: Duration(milliseconds: 800),
curve: Curves.easeInOut,
selectedIndex: currentIndex,
onItemSelected: (index) async {
if (index == 0) {
Navigator.pushNamed(context, Scan.id);
}
if (index == 1) {
Navigator.pushNamed(context, Information.id);
}
if (index == 2) {
Navigator.pushNamed(context, Know.id);
}
if (index == 3) {
SharedPreferences pref = await SharedPreferences.getInstance();
pref.clear();
await _auth.signOut();
Navigator.popAndPushNamed(context, LoginScreen.id);
}
setState(() {
currentIndex = index;
});
},
items: <BottomNavyBarItem>[
BottomNavyBarItem(
icon: Icon(
Icons.camera_alt,
),
title: Text('Scan'),
activeColor: Colors.black,
inactiveColor: Colors.black,
),
BottomNavyBarItem(
icon: Icon(
Icons.perm_device_information,
),
title: Text('Information'),
activeColor: Colors.black,
inactiveColor: Colors.black,
),
BottomNavyBarItem(
icon: Icon(
Icons.open_in_new_outlined,
),
title: Text('Know analysis'),
activeColor: Colors.black,
inactiveColor: Colors.black,
),
],
),
);
}
}
I want a help on how to check each list individually and be able to use the data of the selected list.
this image display my problem
You can do it by storing the selected index in an array.
Here is the idea.
final selectedIndexes = [];
/// In List View
ListView.builder(
itemBuilder: (_, index) {
return Container(
child: Row(
children: [
SizedBox(width: 10),
Checkbox(
value: selectedIndexes.contains(index),
onChanged: (bool value) {
if(selectedIndexes.contains(index) {
selectedIndexes.remove(index); // unselect
} else {
selectedIndexes.add(index); // select
}
setState(() {});
},
checkColor: Colors.greenAccent,
activeColor: Colors.black,
),
Text(
"${sympotms[index]['SymptomsName']}",
style: TextStyle(fontSize: 17.0),
),
],
),
);
},
itemCount: sympotms.length,
)
Since now you have stored the indexes, you can get whatever data you want for selected checkboxes.
Whenever I change the page and come back, the api is reloaded. I have tried many suggestions. I would be glad if you help.
Here are the methods I tried :
How to avoid reloading data every time navigating to page
How to parse JSON only once in Flutter
Flutter Switching to Tab Reloads Widgets and runs FutureBuilder
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'models/Word.dart';
class WordListPage extends StatefulWidget {
WordListPage(Key k) : super(key: k);
#override
_WordListPageState createState() => _WordListPageState();
}
class _WordListPageState extends State<WordListPage> {
Future<List<Word>> data;
bool isSearching = false;
TextEditingController myController = TextEditingController();
List<Word> _words = List<Word>();
List<Word> _wordsForDisplay = List<Word>();
var keyListPage = PageStorageKey('list_page_key');
Future<List<Word>> getWord() async {
var response = await http.get("myAPIurl");
var _words = List<Word>();
_words = (json.decode(utf8.decode(response.bodyBytes)) as List)
.map((singleWordMap) => Word.fromJsonMap(singleWordMap))
.toList();
return _words;
}
#override
void initState() {
getWord().then((value) {
setState(() {
_words.addAll(value);
_wordsForDisplay = _words;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: myFutureBuilder(),
appBar: AppBar(
leading: Center(
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
style: DefaultTextStyle.of(context).style,
children: <TextSpan>[
TextSpan(
text: 'Total',
style: TextStyle(
decoration: TextDecoration.none,
fontSize: 10,
color: Colors.white,
),
),
TextSpan(
text: '\n${_words.length.toString()}',
style: TextStyle(
decoration: TextDecoration.none,
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 12,
),
),
TextSpan(
text: '\nLetter',
style: TextStyle(
decoration: TextDecoration.none,
color: Colors.white,
fontSize: 10,
),
),
],
),
),
),
centerTitle: true,
title: !isSearching
? Text('My Title')
: TextField(
autofocus: true,
style: TextStyle(color: Colors.white),
controller: myController,
onChanged: (value) {
value = value.toLowerCase();
setState(
() {
_wordsForDisplay = _words.where(
(word) {
var wordTitle = word.word.toLowerCase();
return wordTitle.contains(value);
},
).toList();
},
);
setState(
() {
_wordsForDisplay = _words.where(
(word) {
var wordPronounce = word.pronunciation.toLowerCase();
return wordPronounce.contains(value);
},
).toList();
},
);
},
decoration: InputDecoration(
isCollapsed: true,
icon: Icon(
Icons.menu_book,
color: Colors.white,
),
hintText: 'Search',
hintStyle: TextStyle(color: Colors.white),
),
),
actions: [
isSearching
? IconButton(
icon: Icon(Icons.cancel_outlined),
onPressed: () {
setState(
() {
this.isSearching = false;
myController.clear();
_wordsForDisplay = _words.where(
(word) {
var wordTitle = word.word.toLowerCase();
return wordTitle.contains(wordTitle);
},
).toList();
},
);
},
)
: IconButton(
icon: Icon(Icons.search_sharp),
onPressed: () {
setState(
() {
this.isSearching = true;
},
);
},
),
],
),
);
}
FutureBuilder<List<Word>> myFutureBuilder() {
return FutureBuilder(
future: getWord(),
builder: (context, AsyncSnapshot<List<Word>> snapshot) {
if (snapshot.hasData) {
return myWordListView(snapshot);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
);
}
ListView myWordListView(AsyncSnapshot<List<Word>> snapshot) {
return ListView.builder(
itemCount: _wordsForDisplay.length,
itemBuilder: (context, index) {
return ExpansionTile(
title: Text(
_wordsForDisplay[index].word,
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 16.0),
),
subtitle: Text(
snapshot.data[index].pronunciation[0].toUpperCase() +
snapshot.data[index].pronunciation.substring(1),
),
leading: CircleAvatar(
child: Text(snapshot.data[index].word[0]),
),
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: MediaQuery.of(context).size.width,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 7.0, horizontal: 19.0),
child: RichText(
text: TextSpan(
style: DefaultTextStyle.of(context).style,
children: <TextSpan>[
TextSpan(
text: snapshot.data[index].word + ' : ',
style: TextStyle(fontWeight: FontWeight.bold),
),
TextSpan(text: snapshot.data[index].meaning),
],
),
),
),
),
],
),
],
);
},
);
}
}
When you navigate and return back, the build method is called. Here you have "myFutureBuilder" placed as the body widget of Scaffold, thus this code get executed, within it "getWord" method is called, an it fetches data from the api everytime.
I suggest you to remove "myFutureBuider" and use "myWirdListView" directly as the body of the scaffold. Change myWordListView(List<Word> listOfWord) to use the word list you have already fetched in the initState() .
You need to to separate your api call from your ui. That way your api will only get called when you want it to. I recommend using some kind of external state management library, such as Provider, BLoC, or RxDart. Flutter will rebuild a widget anytime it wants to, beyond when you trigger it.
you passed getWord() as a function to you future builder so each time the widget get rebuilt, it is called.
To solve that, declare a variable Future<Word> getWordFuture ; , Inside initState assign getWordFuture = getWord(); and use getWordFuture in the Future builder.
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'models/Word.dart';
class WordListPage extends StatefulWidget {
WordListPage(Key k) : super(key: k);
#override
_WordListPageState createState() => _WordListPageState();
}
class _WordListPageState extends State<WordListPage> {
Future<List<Word>> data;
bool isSearching = false;
TextEditingController myController = TextEditingController();
List<Word> _words = List<Word>();
List<Word> _wordsForDisplay = List<Word>();
var keyListPage = PageStorageKey('list_page_key');
Future<List<Word>> getWordFuture = Future<List<Word>> ; //1
Future<List<Word>> getWord() async {
var response = await http.get("myAPIurl");
var _words = List<Word>();
_words = (json.decode(utf8.decode(response.bodyBytes)) as List)
.map((singleWordMap) => Word.fromJsonMap(singleWordMap))
.toList();
return _words;
}
#override
void initState() {
getWordFuture = getWord(); //2
getWord().then((value) {
setState(() {
_words.addAll(value);
_wordsForDisplay = _words;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: myFutureBuilder(),
appBar: AppBar(
leading: Center(
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
style: DefaultTextStyle.of(context).style,
children: <TextSpan>[
TextSpan(
text: 'Total',
style: TextStyle(
decoration: TextDecoration.none,
fontSize: 10,
color: Colors.white,
),
),
TextSpan(
text: '\n${_words.length.toString()}',
style: TextStyle(
decoration: TextDecoration.none,
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 12,
),
),
TextSpan(
text: '\nLetter',
style: TextStyle(
decoration: TextDecoration.none,
color: Colors.white,
fontSize: 10,
),
),
],
),
),
),
centerTitle: true,
title: !isSearching
? Text('My Title')
: TextField(
autofocus: true,
style: TextStyle(color: Colors.white),
controller: myController,
onChanged: (value) {
value = value.toLowerCase();
setState(
() {
_wordsForDisplay = _words.where(
(word) {
var wordTitle = word.word.toLowerCase();
return wordTitle.contains(value);
},
).toList();
},
);
setState(
() {
_wordsForDisplay = _words.where(
(word) {
var wordPronounce = word.pronunciation.toLowerCase();
return wordPronounce.contains(value);
},
).toList();
},
);
},
decoration: InputDecoration(
isCollapsed: true,
icon: Icon(
Icons.menu_book,
color: Colors.white,
),
hintText: 'Search',
hintStyle: TextStyle(color: Colors.white),
),
),
actions: [
isSearching
? IconButton(
icon: Icon(Icons.cancel_outlined),
onPressed: () {
setState(
() {
this.isSearching = false;
myController.clear();
_wordsForDisplay = _words.where(
(word) {
var wordTitle = word.word.toLowerCase();
return wordTitle.contains(wordTitle);
},
).toList();
},
);
},
)
: IconButton(
icon: Icon(Icons.search_sharp),
onPressed: () {
setState(
() {
this.isSearching = true;
},
);
},
),
],
),
);
}
FutureBuilder<List<Word>> myFutureBuilder() {
return FutureBuilder(
//future: getWord(),
future:getWordFuture,
builder: (context, AsyncSnapshot<List<Word>> snapshot) {
if (snapshot.hasData) {
return myWordListView(snapshot);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
);
}
ListView myWordListView(AsyncSnapshot<List<Word>> snapshot) {
return ListView.builder(
itemCount: _wordsForDisplay.length,
itemBuilder: (context, index) {
return ExpansionTile(
title: Text(
_wordsForDisplay[index].word,
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 16.0),
),
subtitle: Text(
snapshot.data[index].pronunciation[0].toUpperCase() +
snapshot.data[index].pronunciation.substring(1),
),
leading: CircleAvatar(
child: Text(snapshot.data[index].word[0]),
),
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: MediaQuery.of(context).size.width,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 7.0, horizontal: 19.0),
child: RichText(
text: TextSpan(
style: DefaultTextStyle.of(context).style,
children: <TextSpan>[
TextSpan(
text: snapshot.data[index].word + ' : ',
style: TextStyle(fontWeight: FontWeight.bold),
),
TextSpan(text: snapshot.data[index].meaning),
],
),
),
),
),
],
),
],
);
},
);
}
}
I wrote my code in flutter, and used NewsAPI.org for getting content about news, such as heading, image, content etc. I made a class "News" and ArticleModel() for retrieving and using the information. I used Conditional Operator (? :) for checking if the data is received, then show it, else CircularProgressIndiactor() is shown. After running the app, CircularProgressIndiactor() shows up and no information is shown/loaded. Can anyone help me here??
No error or warning is shown, and code compiles successfully, but no information is shown up.
Here is the main file, home.dart -
import 'package:flutter/material.dart';
import 'package:news_app/helper/data.dart';
import 'package:news_app/helper/news.dart';
import 'package:news_app/models/article_model.dart';
import 'package:news_app/models/category_models.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
List<CategoryModel> categories = new List<CategoryModel>();
List<ArticleModel> articles = new List<ArticleModel>();
bool loading = true;
#override
void initState() {
// TODO: implement initState
super.initState();
categories = getCategories();
getNews();
}
getNews() async {
News newsClass = News();
await newsClass.getNews();
articles = newsClass.news;
setState(() {
loading = false;
print('Done');
});
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Flutter',
style: TextStyle(
color: Colors.black,
),
),
Text(
'News',
style: TextStyle(
color: Colors.blue,
),
),
],
),
//elevation: 2.0,
),
body: loading
? Center(
child: Container(
child: CircularProgressIndicator(),
),
)
: SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
///Categories
Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
height: 70.0,
child: ListView.builder(
itemCount: categories.length,
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemBuilder: (context, index) {
return CategoryTile(
imageUrl: categories[index].imageUrl,
categoryName: categories[index].categoryName,
);
},
),
),
///Blogs
Container(
child: ListView.builder(
shrinkWrap: true,
itemCount: articles.length,
itemBuilder: (context, index) {
return BlogTile(
imageUrl: articles[index].urlToImage,
title: articles[index].title,
desc: articles[index].description,
);
},
),
),
],
),
),
),
),
);
}
}
class CategoryTile extends StatelessWidget {
final imageUrl, categoryName;
CategoryTile({this.imageUrl, this.categoryName});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {},
child: Container(
margin: EdgeInsets.only(right: 16.0),
child: Stack(
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(6.0),
child: Image.network(
imageUrl,
width: 120.0,
height: 160.0,
fit: BoxFit.cover,
),
),
Container(
alignment: Alignment.center,
width: 120.0,
height: 60.0,
decoration: BoxDecoration(
color: Colors.black26,
borderRadius: BorderRadius.circular(6.0)),
child: Text(
categoryName,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w500,
fontSize: 14.0,
),
),
),
],
),
),
);
}
}
class BlogTile extends StatelessWidget {
final String imageUrl, title, desc;
BlogTile(
{#required this.imageUrl, #required this.desc, #required this.title});
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Image.network(imageUrl),
Text(title),
Text(desc),
],
),
);
}
}
Here is the News.dart file -
import 'dart:convert';
import 'package:news_app/models/article_model.dart';
import 'package:http/http.dart' as http;
class News {
List<ArticleModel> news = [];
Future<void> getNews() async{
String url="http://newsapi.org/v2/top-headlines?country=in&category=business&apiKey=xxxxxxxxxxxxxxxxxx";
var response = await http.get(url);
var jsonData = jsonDecode(response.body);
if(jsonData["status"] == "ok") {
jsonData["articles"].forEach((element){
if(element['urlToImage'] != null && element['description'] != null) {
ArticleModel articleModel = ArticleModel(
title: element['title'],
author: element['author'],
description: element['description'],
url: element['url'],
urlToImage: element['urlToImage'],
content: element['content'],
);
news.add(articleModel);
}
});
}
}
}
And at last, ArticleModel.dart -
class ArticleModel {
String author, title, description;
String url, urlToImage;
String content;
ArticleModel({this.title, this.description, this.author, this.content, this.url, this.urlToImage});
}
Updating your request URL from http to https will give you expected result.
Update URL to: "https://newsapi.org/v2/top-headlines?country=in&category=business&apiKey="
Note: Don't share your API key in any open platforms for security reasons.
I am using the flutter_staggered_grid_view package (https://github.com/letsar/flutter_staggered_grid_view) to have a feed of images. I want to implement something where first of all I can fetch say 30 images on initial screen load then when I reach the end and the scroll listener fires fetch more from the api. How do I change the below to do this? Can anyone give me any direction on docs etc. I think fundamentally this package is using gridview underneath but I am new to flutter so I'm unsure.
I just want an infinite scroll feed of images from an api.
class HomeScreen extends StatefulWidget {
_HomeState createState() => _HomeState();
}
class _HomeState extends State<HomeScreen> {
final scrollController = ScrollController();
#override
void initState() {
super.initState();
scrollController.addListener(() {
if (scrollController.position.maxScrollExtent ==
scrollController.offset) {
// Get more
print('End of screen');
}
});
}
List<String> imageList = [
'https://cdn.pixabay.com/photo/2020/12/15/16/25/clock-5834193__340.jpg',
'https://cdn.pixabay.com/photo/2020/09/18/19/31/laptop-5582775_960_720.jpg',
'https://media.istockphoto.com/photos/woman-kayaking-in-fjord-in-norway-picture-id1059380230?b=1&k=6&m=1059380230&s=170667a&w=0&h=kA_A_XrhZJjw2bo5jIJ7089-VktFK0h0I4OWDqaac0c=',
'https://cdn.pixabay.com/photo/2019/11/05/00/53/cellular-4602489_960_720.jpg',
'https://cdn.pixabay.com/photo/2017/02/12/10/29/christmas-2059698_960_720.jpg',
'https://cdn.pixabay.com/photo/2020/01/29/17/09/snowboard-4803050_960_720.jpg',
'https://cdn.pixabay.com/photo/2020/02/06/20/01/university-library-4825366_960_720.jpg',
'https://cdn.pixabay.com/photo/2020/11/22/17/28/cat-5767334_960_720.jpg',
'https://cdn.pixabay.com/photo/2020/12/13/16/22/snow-5828736_960_720.jpg',
'https://cdn.pixabay.com/photo/2020/12/15/16/25/clock-5834193__340.jpg',
'https://cdn.pixabay.com/photo/2020/09/18/19/31/laptop-5582775_960_720.jpg',
];
#override
Widget build(BuildContext context) {
/// If you set your home screen as first screen make sure call [SizeConfig().init(context)]
SizeConfig().init(context);
return Scaffold(
body: Platform.isIOS
? Container(
margin: EdgeInsets.only(left: 12, right: 12, top: 5),
child: CustomScrollView(
controller: scrollController,
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
slivers: <Widget>[
SliverAppBar(
floating: true,
title: SvgPicture.asset(
"assets/images/logo-dark.svg",
height: getProportionateScreenWidth(40),
),
actions: [
// Filter Button
FlatButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FilterScreen(),
),
),
child: Text(
"Filter",
style: Theme.of(context).textTheme.bodyText1,
),
),
],
),
CupertinoSliverRefreshControl(
onRefresh: () async {
await Future.delayed(Duration(seconds: 2));
},
),
SliverStaggeredGrid.countBuilder(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 12,
itemCount: imageList.length,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.all(
Radius.circular(15),
),
),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(15)),
child: FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: imageList[index],
fit: BoxFit.cover,
),
),
);
},
staggeredTileBuilder: (index) {
return StaggeredTile.count(1, index.isEven ? 1.2 : 1.8);
},
)
],
),
)
: RefreshIndicator(
color: kMainColor,
displacement: 120,
onRefresh: () async {
await Future.delayed(Duration(seconds: 2));
},
child: Container(
margin: EdgeInsets.only(left: 12, right: 12, top: 5),
child: CustomScrollView(
controller: scrollController,
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics(),
),
slivers: <Widget>[
SliverAppBar(
floating: true,
title: SvgPicture.asset(
"assets/images/logo-dark.svg",
height: getProportionateScreenWidth(40),
),
actions: [
// Filter Button
FlatButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FilterScreen(),
),
),
child: Text(
"Filter",
style: Theme.of(context).textTheme.bodyText1,
),
),
],
),
SliverStaggeredGrid.countBuilder(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 12,
itemCount: imageList.length,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.all(
Radius.circular(15),
),
),
child: ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(15),
),
child: FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: imageList[index],
fit: BoxFit.cover,
),
),
);
},
staggeredTileBuilder: (index) {
return StaggeredTile.count(1, index.isEven ? 1.2 : 1.8);
},
)
],
),
),
),
);
}
}
You need to add the ScrollController for the scrolling detection at the bottom for the ListView and GridView. As you need the GridView i have created the ScrollController listner and added to the GridView's contollerfor the detection of the scroll. I have created the demo of it , please check it once. At first time it load the 10 items and when list comes to the bottom then it add more 10 items in it.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class HomeScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return HomeState();
}
}
class HomeState extends State<HomeScreen> {
List dataList = new List<int>();
bool isLoading = false;
int pageCount = 1;
ScrollController _scrollController;
#override
void initState() {
super.initState();
////LOADING FIRST DATA
addItemIntoLisT(1);
_scrollController = new ScrollController(initialScrollOffset: 5.0)
..addListener(_scrollListener);
}
Widget build(BuildContext context) {
return MaterialApp(
title: 'Gridview',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.red,
accentColor: Color(0xFFFEF9EB),
),
home: Scaffold(
appBar: new AppBar(),
body: GridView.count(
controller: _scrollController,
scrollDirection: Axis.vertical,
crossAxisCount: 2,
mainAxisSpacing: 10.0,
physics: const AlwaysScrollableScrollPhysics(),
children: dataList.map((value) {
return Container(
alignment: Alignment.center,
height: MediaQuery.of(context).size.height * 0.2,
margin: EdgeInsets.only(left: 10.0, right: 10.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
),
child: Text("Item ${value}"),
);
}).toList(),
)));
}
//// ADDING THE SCROLL LISTINER
_scrollListener() {
if (_scrollController.offset >=
_scrollController.position.maxScrollExtent &&
!_scrollController.position.outOfRange) {
setState(() {
print("comes to bottom $isLoading");
isLoading = true;
if (isLoading) {
print("RUNNING LOAD MORE");
pageCount = pageCount + 1;
addItemIntoLisT(pageCount);
}
});
}
}
////ADDING DATA INTO ARRAYLIST
void addItemIntoLisT(var pageCount) {
for (int i = (pageCount * 10) - 10; i < pageCount * 10; i++) {
dataList.add(i);
isLoading = false;
}
}
#override
void dispose() {
_scrollController.dispose();
super.dispose();
}
}
https://i.stack.imgur.com/7hcDc.gif
hello i am new to flutter and i m using update profile api in my profile api i describe all parameter and image base 64 also now what is going on ! suppose alredy is image showing on my profile pic and i never pic image from my camera and device My "Profile Pic" parameter showing null when i call it...! and when i picke image from my device it showing base 64...! what i want is if there is alredy image showing then profile api function i want success because there is alredy image shown ... now u suggest me when i call Profile api function on my Button wht i need to pass
PickedFile _imageFile;
final ImagePicker _picker = ImagePicker();
String img64;
void takePhoto(ImageSource source) async {
final pickedFile = await _picker.getImage(source: source);
setState(() {
_imageFile = pickedFile;
final bytes = Io.File(_imageFile.path).readAsBytesSync();
img64 = base64Encode(bytes);
print(img64.substring(0, 100));
});
}
Profile(String FirstnName,String Lastname,String Email,String DOB,String
Anniversary) async {
sharedPreferences = await SharedPreferences.getInstance();
ValidateCustomer();
Map data =
{
"AccessToken": sharedPreferences.getString("AccessToken"),
"CustomerId": sharedPreferences.getInt("CustomerId"),
"FirstName": FirstnName ,
"LastName": Lastname,
"Email": Email,
"DOB":DOB,
"AnniversaryDate": Anniversary,
"ProfilePicture" : img64
};
print(data);
final http.Response response = await http.post(
Constants.CUSTUMER_WEBSERVICE_UPDATEPROF_URL,
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(data),
);
var jsonResponse;
if (response.statusCode == 200)
{
print(sharedPreferences.setString("FirstName", FirstnName));
jsonResponse = json.decode(response.body);
sharedPreferences = await SharedPreferences.getInstance();
sharedPreferences.setString("FirstName", FirstnName);
sharedPreferences.setString("ProfilePicture",img64);
print("Response status : ${response.statusCode}");
print("Response status : ${response.body}");
print(sharedPreferences);
if(jsonResponse != null && ! jsonResponse.containsKey("Error")){
setState(() {
_isLoading = false;
});
print(sharedPreferences);
Navigator.of(context).push(
MaterialPageRoute(builder: (context)=>
ShelfScreen())
);
}
else{
setState(() {
_isLoading = false;
});
print("Response status : ${response.body}");
}
}
if (response.statusCode == 404){
print("Response status : ${response.statusCode}");
print("Response status : ${response.body}");
}
}
Future<UserUpdate>ProfileUpadte() async {
sharedPreferences = await SharedPreferences.getInstance();
ValidateCustomer();
Map data =
{
"AccessToken": sharedPreferences.getString("AccessToken"),
"CustomerId": sharedPreferences.getInt("CustomerId"),
};
print(data);
final http.Response response = await http.post(
"http://api.pgapp.in/v1/userdetails",
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(data),
);
if (response.statusCode == 200)
{
print("Response status : ${response.statusCode}");
print("Response status : ${response.body}");
var jsonResponse = json.decode(response.body);
if(jsonResponse != null && ! jsonResponse.containsKey("Error")){
sharedPreferences = await SharedPreferences.getInstance();
sharedPreferences.setString("ProfilePicture",
jsonResponse["ProfilePicture"]);
sharedPreferences.setString("FirstName", jsonResponse["FirstName"]);
print(sharedPreferences);
}
else{
setState(() {
_isLoading = false;
});
print("Response status : ${response.body}");
}
return UserUpdate.fromJson(json.decode(response.body));
}
else {
// If the server did not return a 201 CREATED response,
// then throw an exception.
throw Exception('Failed to load data');
}
}
void nextField ({String value,FocusNode focusNode}){
if (value.isNotEmpty){
focusNode.requestFocus();
}
}
AnimationController _controller;
Animation _animation;
FocusNode _focusNode1 = FocusNode();
bool _isLoading = false;
String _Firstnm;
String _Lastnm;
String _Mobno;
String _Email;
String _Dob;
String _Anniversary;
DateTime _selectedDate;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
FocusNode Firstname;
FocusNode LastndName;
FocusNode Email;
FocusNode DOB;
FocusNode Anniversary;
Future<UserUpdate> _futureProfileupdate;
#override
void initState() {
// TODO: implement initState
super.initState();
Firstname = FocusNode();
LastndName = FocusNode();
Email = FocusNode();
DOB = FocusNode();
Anniversary = FocusNode();
_futureProfileupdate = ProfileUpadte();
}
void _showPicker(context) {
showModalBottomSheet(
context: context,
builder: (BuildContext bc) {
return SafeArea(
child: Container(
child: new Wrap(
children: <Widget>[
new ListTile(
leading: new Icon(Icons.photo_library),
title: new Text('Photo Library'),
onTap: () {
takePhoto(ImageSource.gallery);
Navigator.of(context).pop();
}),
new ListTile(
leading: new Icon(Icons.photo_camera),
title: new Text('Camera'),
onTap: () {
takePhoto(ImageSource.camera);
Navigator.of(context).pop();
},
),
],
),
),
);
}
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
resizeToAvoidBottomPadding: false,
body: (_isLoading) ? Center(child: CircularProgressIndicator()) :
FutureBuilder<UserUpdate>(
future: _futureProfileupdate,
builder: (context, snapshot) {
if (snapshot.hasData) {
TextEditingController _textEditingControllerFirstNamee =
TextEditingController(text: snapshot.data.firstName);
TextEditingController _textEditingControllerLastnamee = TextEditingController(text: snapshot.data.lastName);
TextEditingController _textEditingControllerEmaill = TextEditingController(text: snapshot.data.email);
TextEditingController _textEditingControllerDOBb = TextEditingController(text: snapshot.data.dob);
TextEditingController _textEditingControllerAnniversaryy = TextEditingController(text: snapshot.data.anniversaryDate);
_selectDate(BuildContext context) async {
DateTime newSelectedDate = await showDatePicker(
context: context,
initialDate: _selectedDate != null ? _selectedDate : DateTime.now(),
firstDate: DateTime(1920),
lastDate: DateTime(2040),
builder: (BuildContext context, Widget child) {
return Theme(
data: ThemeData.dark().copyWith(
colorScheme: ColorScheme.dark(
primary: Colors.deepPurple,
onPrimary: Colors.white,
surface: Colors.blueGrey,
onSurface: Colors.yellow,
),
dialogBackgroundColor: Colors.blue[500],
),
child: child,
);
});
if (newSelectedDate != null) {
_selectedDate = newSelectedDate;
_textEditingControllerDOBb
..text = DateFormat.yMMMd().format(_selectedDate)
..selection = TextSelection.fromPosition(TextPosition(
offset: _textEditingControllerDOBb.text.length,
affinity: TextAffinity.upstream));
}
}
_selectDate2(BuildContext context) async {
DateTime newSelectedDate = await showDatePicker(
context: context,
initialDate: _selectedDate != null ? _selectedDate : DateTime.now(),
firstDate: DateTime(1920),
lastDate: DateTime(2040),
builder: (BuildContext context, Widget child) {
return Theme(
data: ThemeData.dark().copyWith(
colorScheme: ColorScheme.dark(
primary: Colors.deepPurple,
onPrimary: Colors.white,
surface: Colors.blueGrey,
onSurface: Colors.yellow,
),
dialogBackgroundColor: Colors.blue[500],
),
child: child,
);
});
if (newSelectedDate != null) {
_selectedDate = newSelectedDate;
_textEditingControllerAnniversaryy
..text = DateFormat.yMMMd().format(_selectedDate)
..selection = TextSelection.fromPosition(TextPosition(
offset: _textEditingControllerAnniversaryy.text.length,
affinity: TextAffinity.upstream));
}
}
return Form(
key: _formKey,
child: Stack(
children: <Widget>[
Positioned(
left: 20,
top: 40,
child: Center(
child: Image.asset(
'assets/images/logo.png', height: 50, width: 50,),
)
),
Positioned(
left: 60,
right: 60,
top: 40,
child: Center(
child: Image.asset(
'assets/images/Textimage.png', height: 50,
width: 170,),
)
),
Positioned(
right: 20,
top: 40,
child: Center(
child: IconButton(
icon: Icon(Icons.exit_to_app, size: 30,
color: Color(0xfff58634),),
onPressed: () async {
showAboutDialog(context);
},
)
)
),
Positioned(
left: 70,
right: 70,
top: 110,
child: Center(
child: CircleAvatar(
backgroundImage: _imageFile == null ? NetworkImage(
snapshot.data.profilePicture) : FileImage(Io.File(_imageFile.path)),
backgroundColor: Colors.grey,
maxRadius: 50,
)
)
),
Positioned(
left: 100,
right: 70,
top: 170,
child: InkWell(
onTap: (){
_showPicker(context);
},
child: Icon(
Icons.camera_alt,
color: Colors.white,
size: 30,
),
),
),
Positioned(
left: 30,
right: 30,
top: 250,
child: Container(
height: 480,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 5),
child: SizedBox(
height: 70,
child: TextFormField(
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.sentences,
textInputAction: TextInputAction.next,
focusNode: Firstname,
onFieldSubmitted: (value) {
nextField(
value: value, focusNode: LastndName);
},
controller: _textEditingControllerFirstNamee,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(
5.0),
borderSide: BorderSide(
color: const Color(0x3df58634)
)
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(
5.0)
),
labelText: "First Name",
labelStyle: GoogleFonts.nunito(
color: const Color(0xfff58634)),
hintText: "First Name",
hintStyle: GoogleFonts.nunito(
color: const Color(0xfff58634)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(
5.0),
borderSide: BorderSide(
color: const Color(0x3df58634),
)
),
),
validator: (String value) {
if (value.isEmpty) {
return 'First Name is Required';
}
return null;
},
onSaved: (String value) {
_Firstnm = value;
},
),
),
),
Padding(
padding: const EdgeInsets.only(top: 5),
child: SizedBox(
height: 70,
child: TextFormField(
keyboardType: TextInputType.text,
textCapitalization:
TextCapitalization.sentences,
focusNode: LastndName,
textInputAction: TextInputAction.next,
onFieldSubmitted: (value) {
nextField(value: value, focusNode:
Email);
},
controller:
_textEditingControllerLastnamee,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(
5.0),
borderSide: BorderSide(
color: const Color(0x3df58634)
)
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(
5.0)
),
labelText: 'Last Name',
labelStyle: GoogleFonts.nunito(
color: const Color(0xfff58634)),
hintText: "Last Name",
hintStyle: GoogleFonts.nunito(
color: const Color(0xfff58634)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(
5.0),
borderSide: BorderSide(
color: const Color(0x3df58634),
)
),
),
validator: (String value) {
if (value.isEmpty) {
return 'First Name is Required';
}
return null;
},
onSaved: (String value) {
_Lastnm = value;
},
),
),
),
Padding(
padding: const EdgeInsets.only(top: 5),
child: SizedBox(
height: 70,
child: TextFormField(
focusNode: Email,
textInputAction: TextInputAction.next,
onFieldSubmitted: (value) {
nextField(value: value, focusNode: DOB);
},
controller: _textEditingControllerEmaill,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(
5.0),
borderSide: BorderSide(
color: const Color(0x3df58634)
)
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(
5.0)
),
labelText: 'Email',
labelStyle: GoogleFonts.nunito(
color: const Color(0xfff58634)),
hintText: "Email",
hintStyle: GoogleFonts.nunito(
color: const Color(0xfff58634)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(
5.0),
borderSide: BorderSide(
color: const Color(0x3df58634),
)
),
),
validator: (value) => EmailValidator.validate(value) ? null : "Please enter a valid email",
onSaved: (String value) {
_Email = value;
},
),
),
),
Padding(
padding: EdgeInsets.only(top: 45),
child: SizedBox(
width: 360,
height: 45,
child: RaisedButton(
onPressed: () {
if (!_formKey.currentState.validate()) {
return;
}
setState(() {
_isLoading = true;
});
Profile(
_textEditingControllerFirstNamee.text,
_textEditingControllerLastnamee.text,
_textEditingControllerEmaill.text,
_textEditingControllerDOBb.text,
_textEditingControllerAnniversaryy
.text,);
Navigator.of(context).push(MaterialPageRoute(builder: (context) => ShelfScreen()));
},
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(
5.0)),
color: const Color(0xfff58634),
child: Text(
"Update",
style: GoogleFonts.nunito(
color: const Color(0xffffffff),
fontSize: 20
),
),
),
),
),
Padding(
padding: EdgeInsets.only(top: 120),
child: Text(".", style: TextStyle(
color: Colors.transparent, fontSize: 1,
),),
)
],
),
),
),
),
],
),
);
} else {
return CircularProgressIndicator();
);
}
}
)
);
}
}
class AlwaysDisabledFocusNode extends FocusNode {
#override
bool get hasFocus => false;
}