Related
In my app, I have a login page connected to Firebase. I can successfully log in but when logging in, I want to display a CircularProgressIndicator until login is a success.
void signIn(String email, String password) async {
if (_formKey.currentState!.validate()) {
await _auth
.signInWithEmailAndPassword(email: email, password: password)
.then((_userDoc) => {
checkUserType(_userDoc.user!.uid),
})
.catchError((e) {
print('Error');
);
});
}
}
create a isLoading variable, set its state to true at the start of the sign-in, and false after the promise has been fulfilled.
then show the CircularProgressIndicator while isLoading = true
This will replace login button with CircularProgressIndicator while loading.
void signIn() async {
setState(() {
isLoading = true;
});
Future.delayed(Duration(seconds: 1)).then((value) {
/// loginOperationhere
//end of login set false, also include on catch method
setState(() {
isLoading = false;
});
});
}
bool isLoading = false; // on state class level
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
isLoading
? CircularProgressIndicator()
: ElevatedButton(
onPressed: () {
signIn();
},
child: Text("login"),
)
],
));
}
}
Try below code hope its helpful to you.
Create bool variable
bool _isLoading = false;
Your Widget:
Center(
child: !_isLoading
? Container(
width: MediaQuery.of(context).size.width,
height: 50.0,
padding: EdgeInsets.symmetric(horizontal: 15.0),
margin: EdgeInsets.only(top: 15.0),
// ignore: deprecated_member_use
child: ElevatedButton(
child: Text(
'Sign In',
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
textAlign: TextAlign.center,
),
onPressed: () {
// Your Login function call
setState(() {
_isLoading = true;
});
},
),
)
: CircularProgressIndicator(),
),
Your Widget using Center:
!_isLoading
? Center(
child: Container(
width: MediaQuery.of(context).size.width,
height: 50.0,
padding: EdgeInsets.symmetric(horizontal: 15.0),
margin: EdgeInsets.only(top: 15.0),
// ignore: deprecated_member_use
child: ElevatedButton(
child: Text(
'Sign In',
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
textAlign: TextAlign.center,
),
onPressed: () {
// Your Login function call
setState(() {
_isLoading = true;
});
},
),
),
)
: Center(
child: CircularProgressIndicator(),
),
Your result screen before pressed on button ->
Your result screen after button pressed->
I'm getting the below PlatformException in a FutureBuilder when running app.release.apk on an Android phone. It doesn't happen every time.
I noticed that if I have the app open and I close the phone, after opening it and visiting the first item from a ListView shows the error, sometimes following visits to other items causes the exception, sometimes not.
PlatformException(Error performing get, Failed to get document because the client is offline., null
class _ItemState extends State<Item> {
Future _itemFuture;
#override
void initState() {
setState(() {
_itemFuture = Firestore.instance
.collection('content')
.document(widget.item.documentID)
.get();
});
...
super.initState();
}
Scaffold(
body: Container(
child: FutureBuilder<DocumentSnapshot>(
future: _itemFuture,
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Container();
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(),
);
default:
if (snapshot.hasError) {
return Text('Error1: ${snapshot.error}');
} else {
if (snapshot.hasData) {
return _itemBody(
snapshot.data,
);
}
}
return null;
}
},
),
),
);
I am using:
cloud_firestore: ^0.13.7
firebase_auth: ^0.16.1
*** Edit
I will add the whole widget. I cleaned it, removing any other logic that I thought might cause the error. Now it's a minimal widget that makes a request to Firestore using Streambuilder. Of course with the same error.
class Item extends StatefulWidget {
Item({
Key key,
this.items,
this.showAd,
this.user,
this.item,
this.favorites,
}) : super(key: key);
final List<Imodel> items;
final bool showAd;
final UserModel user;
final item;
final List<FireFavorites> favorites;
#override
_ItemState createState() => _ItemState();
}
class _ItemState extends State<Item> {
DateTime _lastViewed;
bool _viewRequest = true;
final _adWidget = AdMobWidget();
bool _favoriteItem = false;
#override
void initState() {
super.initState();
final isFavorite = widget.favorites
.where((element) => element.id == widget.item.documentID);
if (isFavorite.length > 0) {
_favoriteItem = true;
}
}
#override
Widget build(BuildContext context) {
if (widget.showAd) {
_adWidget.showAd();
}
final _headerStyle = TextStyle(fontWeight: FontWeight.bold);
Widget _itemBody(item) {
return ListView(
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
...
],
),
],
);
}
_future() {
return FutureBuilder<DocumentSnapshot>(
future: Firestore.instance
.collection('content')
.document(widget.item.documentID)
.get(source: Source.serverAndCache),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
List<Widget> children;
if (snapshot.hasData) {
children = <Widget>[Expanded(child: _itemBody(snapshot.data))];
} else if (snapshot.hasError) {
children = <Widget>[
Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
)
];
} else {
children = <Widget>[
SizedBox(
child: CircularProgressIndicator(),
width: 60,
height: 60,
),
const Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
];
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
),
);
},
);
}
return Scaffold(
resizeToAvoidBottomPadding: false,
backgroundColor: Color(0xff2398C3),
appBar: AppBar(
elevation: 0,
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Color(0xff042C5C), Color(0xff2398C3)],
),
),
),
actions: <Widget>[
BookmarkIcon(
isFav: _favoriteItem,
documentID: widget.item.documentID,
userID: widget.user.uid,
),
Padding(
padding: EdgeInsets.only(
right: 20.0,
),
child: GestureDetector(
onTap: () {},
child: Icon(
Icons.share,
size: 18.0,
),
),
),
],
),
body: Container(
width: double.infinity,
height: double.infinity,
padding: EdgeInsets.only(
top: 25.0,
left: 30.0,
right: 15.0,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(32),
topRight: Radius.circular(32),
),
),
child: widget.item.documentID != null ? _future() : Container(),
),
);
}
}
Currently i develop a Meal and Shopping App. In this App you can Add what you want to Eat next and have the secound Tab, Shopping where you can Add your Items you want to buy next. Created is that a User can invite another User to edit together the List.
I get the Error shown below. I can't figure out how to return the Container. At the void saveInviteToFirestore the user is not used do I need that it used?
Code
import 'package:flutter/material.dart';
import 'package:mealapp/models/Widgets/whenAndWhatToEat.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:intl/intl.dart';
import 'package:mealapp/models/global.dart';
import 'package:status_alert/status_alert.dart';
import 'package:firebase_auth/firebase_auth.dart';
class MealTile extends StatefulWidget {
final MealsAndWhen mealsAndWhen;
MealTile({this.mealsAndWhen});
#override
MealTileState createState() {
return MealTileState();
}
}
class MealTileState extends State<MealTile> {
String id;
final db = Firestore.instance;
String mail;
List<String> authors = [];
DateTime selectedDate = DateTime.now();
Future pickDate() async {
DateTime datepick = await showDatePicker(
context: context,
initialDate: new DateTime.now(),
firstDate: new DateTime.now().add(Duration(days: -0)),
lastDate: new DateTime.now().add(Duration(days: 365)));
if (datepick != null)
setState(() {
selectedDate = datepick;
});
}
Future<String> inputData() async {
final FirebaseUser user = await FirebaseAuth.instance.currentUser();
return user != null ? user.uid : null;
}
Future<String> inputDataMail() async {
final FirebaseUser user = await FirebaseAuth.instance.currentUser();
return user != null ? user.email : null;
}
String userId;
void _getUserId() {
inputData().then((value) => setState(() {
userId = value;
}));
}
String currentMail;
void _getMail(doc) {
inputDataMail().then((value) => setState(() {
currentMail = value;
}));
}
/*void _getAuthors(DocumentSnapshot doc) async {
authors = [];
//if (await FirebaseAuth.instance.currentUser() != null) {
authors = List.from(doc.data['Authors']);
print(doc.data['authors']);
//authors.insert(0, currentMail);
//}
}*/
Widget buildItem(DocumentSnapshot doc) {
DateTime now = doc.data['Date'].toDate();
DateFormat formatter = DateFormat('dd-MM-yyyy');
String formatted = formatter.format(now);
_getUserId();
_getMail(doc);
if (doc.data['Authors'] != null) {
//_getAuthors(doc);
//print('Current mail: ' + currentMail + authors.toString() + doc.data['Author'] + doc.data['Meal']);
}
if (now.day == DateTime.now().day) { // If the Date of the meal is today
deleteData(doc, false); // Delete it!
}
// You could also change ".day" to ".hour".
// Example: if (now.day == DateTime.now().day && now.hour == DateTime.hour())
// So, if a meal is set for 2PM, it will delete at 2PM
return FutureBuilder<FirebaseUser>(
future: FirebaseAuth.instance.currentUser(),
builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot) {
if (snapshot.hasData && snapshot != null) {
return Container(
margin: const EdgeInsets.all(8.0),
child: currentMail == doc.data['Author'] || // If the current mail is the author
List.from(doc.data['Authors']).contains(currentMail) // Or if the current mail is part of the authors
? Column( // then if true, show a Column
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'Meal:',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white),
textAlign: TextAlign.center,
),
Text(
'${doc.data['Meal']}',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white),
textAlign: TextAlign.center,
),
SizedBox(height: 20),
Text(
'When:',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white),
textAlign: TextAlign.center,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
onPressed: () => updateData(doc),
color: lightBlueColor,
icon: Icon(Icons.calendar_today,
color: Colors.white),
tooltip: 'Update Date',
),
Text(
formatted,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white),
textAlign: TextAlign.center,
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
SizedBox(width: 8),
FlatButton(
color: Colors.red,
onPressed: () => deleteData(doc, true),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadiusDirectional.circular(12)),
child: Row(children: <Widget>[
Text('Delete',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white)),
Icon(Icons.delete_forever, color: Colors.white),
]),
),
SizedBox(width: 8),
FlatButton(
color: Colors.blue,
onPressed: () => [
showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
child: invite(doc),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(12)),
),
);
})
],
shape: RoundedRectangleBorder(
borderRadius:
BorderRadiusDirectional.circular(12)),
child: Row(children: <Widget>[
Text('Invite',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white)),
Icon(Icons.share, color: Colors.white),
]),
),
],
),
],
)
: Text(''), // if false, show an empty text widget
decoration: BoxDecoration(
color: lightBlueColor,
borderRadius: BorderRadius.all(Radius.circular(12)),
),
);
}
/*Navigator.pop(context);
return HomePage();*/
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: darkGreyColor,
body: ListView(
padding: EdgeInsets.only(top: 220),
children: <Widget>[
StreamBuilder<QuerySnapshot>(
stream: db
.collection('mealList')
.orderBy('Date', descending: false) // Order by Date, not descending
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: snapshot.data.documents
.map((doc) => buildItem(doc))
.toList());
} else {
return Container();
}
},
),
],
),
);
}
/*share(BuildContext context, DocumentSnapshot doc) {
final RenderBox box = context.findRenderObject();
final dynamic date = timeago.format(doc['Date'].toDate());
Share.share(
"${doc['Meal']} - $date",
subject: doc['Meal'],
sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size,
);
}*/
Widget invite(DocumentSnapshot doc) {
final _formKey = GlobalKey<FormState>();
return Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
Center(
child: Text(
"Invite someone by mail",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
)),
SizedBox(
height: 24,
),
TextFormField(
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12))),
labelText: 'Enter the email address'),
validator: (value) {
if (value.isEmpty) {
return 'Please enter an email address';
}
return null;
},
onSaved: (value) => mail = value,
),
FlatButton(
onPressed: () async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
saveInviteToFirestore(doc, mail);
}
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12))),
child: Text("Save"),
color: redColor,
textColor: Colors.white,
),
]),
),
);
}
Future<String> getCurrentUser() async {
return await FirebaseAuth.instance.currentUser().then((value) => value.uid);
}
void saveInviteToFirestore(DocumentSnapshot doc, String email) async {
final String user = await getCurrentUser();
var list = List<String>();
list.add(email);
Firestore.instance
.collection('mealList')
.document(doc.documentID)
.updateData({"Authors": FieldValue.arrayUnion(list)});
//setState(() => id = doc.documentID);
StatusAlert.show(
context,
duration: Duration(seconds: 2),
title: 'Added',
subtitle: 'You have Added your and the Date to your List',
configuration: IconConfiguration(icon: Icons.done),
);
//Navigator.pop(context);
}
void deleteData(DocumentSnapshot doc, bool showMessage) async {
await db.collection('mealList').document(doc.documentID).delete();
setState(() => id = null);
if (showMessage) {
StatusAlert.show(
context,
duration: Duration(seconds: 2),
title: 'Deleted',
subtitle: 'You have Deleted your Meal',
configuration: IconConfiguration(icon: Icons.delete),
);
}
}
void updateData(DocumentSnapshot doc) async {
await pickDate();
await db
.collection('mealList')
.document(doc.documentID)
.updateData({'Date': selectedDate});
StatusAlert.show(
context,
duration: Duration(seconds: 2),
title: 'Updated',
subtitle: 'You have updated your Meal Date',
configuration: IconConfiguration(icon: Icons.done),
);
}
}
Error
The following assertion was thrown building FutureBuilder<FirebaseUser>(dirty, state: _FutureBuilderState<FirebaseUser>#a4504):
A build function returned null.
The offending widget is: FutureBuilder<FirebaseUser>
Build functions must never return null.
To return an empty space that causes the building widget to fill available room, return "Container()". To return an empty space that takes as little room as possible, return "Container(width: 0.0, height: 0.0)".
The relevant error-causing widget was
FutureBuilder<FirebaseUser>
lib/…/MealPlan/mealTile.dart:92
When the exception was thrown, this was the stack
#0 debugWidgetBuilderValue.<anonymous closure>
package:flutter/…/widgets/debug.dart:276
In your FutureBuilder you are not returning anything when the Future hasn't completed yet. A widget always needs to be returned whether there is data or not.
Example fix for your code:
return FutureBuilder<FirebaseUser>(
future: FirebaseAuth.instance.currentUser(),
builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot) {
if (snapshot.hasData && snapshot != null) {
return Container(
...
);
}
//ADDED ELSE BLOCK
else {
return Container();
}
}
);
Or as #stacker suggested, you can return a CircularProgressIndicator().
I am trying to fetch my currentUser using FutureBuilder in my main.dart file:
//my auth.dart file
class Auth {
final FirebaseAuth _auth = FirebaseAuth.instance;
Future getUser() {
return _auth.currentUser();
}
}
class MyApp extends StatelessWidget {
Auth auth = Auth();
#override
Widget build(BuildContext context) {
return MaterialApp(
home: FutureBuilder(
future: auth.getUser(),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.error != null) {
print("$snapshot.error.toString()");
return Container();
}
if (snapshot.hasData) {
return BottomBar(
firebaseUser: snapshot.data, visibleLogin: false);
} else if (snapshot.data == null) {
return BottomBar(
firebaseUser: null,
visibleLogin: true,
);
}
}
return CircularProgressIndicator();
}),
);
}
}
//Update, tried using StreamBuilder
StreamBuilder<FirebaseUser>(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (BuildContext context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.data.uid!=null) {
return BottomBar(
firebaseUser: snapshot.data, visibleLogin: false);
} else {
return BottomBar(
firebaseUser: null,
visibleLogin: true,
);
}
}
return CircularProgressIndicator();
}),
Whenever my user logs in, I pass the user in my bottom navigation bar, which then passes the data to all my pages.
My login is in the same page as my home page, so whenever my user logs in, I want to hide the login part in my home page.
Widget login(bool visibleLogin) {
return Visibility(
visible: visibleLogin,
child: Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.only(bottom: 78.0),
child: Container(
height: 90,
color: Colors.transparent,
margin: EdgeInsets.fromLTRB(8.0, 0.0, 8.0, 0.0),
child: Container(
child: Container(
margin: EdgeInsets.only(top: 20.0),
child: Column(
children: [
Padding(
padding: EdgeInsets.only(top: 5.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTap: () => auth.signInWithGoogle(),
child: Container(
padding: EdgeInsets.all(10.0),
child: Icon(
FontAwesome.google,
color: kOrange,
),
),
),
],
),
),
],
),
),
),
),
),
),
);
}
When my user logs in, the UI of my app doesn't get updated automatically by my FutureBuilder, hence I call the onAuthStateChanged listener in my initState() of my homepage:
void isSignedIn() {
_auth.onAuthStateChanged.listen((user) {
if (user != null) {
setState(() {});
} else {
print('no user');
}
});
}
}
After checking, this method is getting triggered, but my UI only gets updated when I shut and relaunch my app. How do I update my UI as soon as my user logs in?
I think this is not possible with FutureBuilder, you have to use StreamBuilder for this Functionality.
As once Future is complete it will not look for any change, where as if you use stream then whenever new data arrives it will change data.
Update:
You even don't need to change any variable or call any method, now just check snap and show screen accordingly. make to check connection status is done because until that time it will return null even user is login.
StreamBuilder(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (_, snap) {
if(snap.connectionState == ConnectionState.active){
if(snap.data == null){
// return with out login
}else{
// return login
}
}else{
return CircularProgressIndicator();
}
},
),
Update:
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
StreamBuilder(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (_, snap) {
print(snap.connectionState);
if (snap.connectionState == ConnectionState.active) {
print(snap.data.toString());
if (snap.data == null) {
return Text("not login");
} else {
return Text("login");
}
} else {
return CircularProgressIndicator();
}
},
),
RaisedButton(
child: Text("hello"),
onPressed: () {
var a = FirebaseAuth.instance.signInAnonymously();
print(a);
},
),
RaisedButton(
child: Text("Log out"),
onPressed: () {
var a = FirebaseAuth.instance.signOut();
print(a);
},
)
],
),
I have a button which onpressed inserts something in DB and redirects user to another page. I am trying to implement FutureBuilder which should show CircularProgressIndicator until everything is done.
This is my function:
Future<bool> insertPhoneNumber(String phoneNumber) async {
String token = await getToken();
if (token.isNotEmpty) {
var body = jsonEncode({'token': token, 'userID': user.getUserID(), 'phoneNumber': phoneNumber});
print(body.toString());
var res = await http.post((baseUrl + "/insertPhoneNumber/" + user.getUserID()),
body: body,
headers: {
"Accept": "application/json",
"content-type": "application/json"
});
if (res.statusCode == 200) {
print("Insert Phone Number is OK");
notifyListeners();
return true;
} else {
print("Insert Phone Number not OK");
notifyListeners();
return false;
}
} else {
print("Insert Phone Number failed due to unexisting token");
}
}
and this is a button which triggers DB interaction:
RaisedButton(
color: Color.fromRGBO(105, 79, 150, 1),
onPressed: () {
var user = Provider.of<UserRepository>(context);
String completePhoneNumber = _selectedDialogCountry.phoneCode + phoneNumberController.text;
FutureBuilder(
future: user.insertPhoneNumber(completePhoneNumber),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return CircularProgressIndicator(
backgroundColor: Colors.blue);
} else {
return Dashboard();
}
},
);
},
textColor: Colors.white,
child: Text("SAVE"),
)
It updates DB but nothing else happens. There is no progress indicator nor redirection to Dashboard.
EDIT
This is my full build method:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
AutoSizeText(
'What is your phone number?',
style: TextStyle(fontSize: 30),
maxLines: 1,
),
Row(
children: <Widget>[
SizedBox(
width: 9.0,
child: Icon(Icons.arrow_downward),
),
SizedBox(width: 8.0),
SizedBox(
width: 120.0,
height: 65.0,
child: Card(
child: ListTile(
onTap: _openCountryPickerDialog,
title: _buildDialogItem(_selectedDialogCountry),
),
)),
Expanded(
child: TextField(
autofocus: true,
keyboardType: TextInputType.number,
decoration:
InputDecoration(border: OutlineInputBorder())),
),
],
),
SizedBox(
width: 100,
child: RaisedButton(
color: Color.fromRGBO(105, 79, 150, 1),
onPressed: () {
print("Test");
},
textColor: Colors.white,
child: Text("SAVE"),
),
)
],
)),
);
}
It is not working because the FutureBuilder isn't attached to the Widget tree.
The once the future is not in done state, it is just creating an instance Dashboard.You shouldn't be using FutureBuilder here instead you can set the child widget based on some variable and when future complete, you call setState on the that variable to update the state which will in-turn rebuild the widget with the new state value
Something like this
var isLoading = false;
void insertNumber(){
var user = Provider.of<UserRepository>(context);
String completePhoneNumber = _selectedDialogCountry.phoneCode + phoneNumberController.text;
setState(() => isLoading=true);
user.insertPhoneNumber(completePhoneNumber).then((result){
setState(() => isLoading=false);
})
}
Widget build(BuildContext context){
return RaisedButton(
color: Color.fromRGBO(105, 79, 150, 1),
onPressed: () {
var user = Provider.of<UserRepository>(context);
String completePhoneNumber = _selectedDialogCountry.phoneCode + phoneNumberController.text;
FutureBuilder(
future: user.insertPhoneNumber(completePhoneNumber),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return CircularProgressIndicator(
backgroundColor: Colors.blue);
} else {
return Dashboard();
}
},
);
},
textColor: Colors.white,
child: isLoading? CircularProgressIndicator(): Text("Save"),
);
}
For your use case, you will need more that two state to achieve the UI you are looking for .Example DEFAULT,LOADING,ERROR,SUCCESS