I am developing a login form with flutter. When the user click on submit button it will connect with Firebase Auth to see credentials and sign in the user. Until that process i NEED TO show the user a CircularProgressBar. To see whether the sign in process is complete or not, I am using FutureBuilder. Below is my code
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
class LoginPage extends StatelessWidget {
LoginPage() {}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color.fromRGBO(11, 51, 83, 90),
Color.fromRGBO(4, 18, 30, 1)
])),
child: LoginForm()),
);
}
}
class LoginForm extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return LoginFormState();
}
}
class LoginFormState extends State<LoginForm> {
final _formKey = GlobalKey<FormState>();
final FirebaseAuth _auth = FirebaseAuth.instance;
TextEditingController emailController = TextEditingController();
TextEditingController passwordController = TextEditingController();
#override
Widget build(BuildContext context) {
// TODO: implement build
return ListView(
children: <Widget>[
Container(
child: _buildLogo(),
margin:
EdgeInsets.only(top: MediaQuery.of(context).size.height * 0.20),
),
Container(
child: _buildForm(),
margin: EdgeInsets.only(left: 10, right: 10, top: 83),
)
],
);
}
Widget _buildLogo() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(
"assets/images/logo.png",
fit: BoxFit.fill,
)
],
);
}
Widget _buildForm() {
return Form(
key: _formKey,
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
flex: 1,
child: Container(
child: Icon(
Icons.person,
color: Colors.white,
),
// child: ImageIcon(
// AssetImage("assets/images/email_24px.png"),
// color: Colors.white,
// ),
margin: EdgeInsets.only(right: 5, bottom: 10)),
),
Flexible(
flex: 7,
child: SizedBox(
height: 60,
child: TextFormField(
controller: emailController,
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
contentPadding:
const EdgeInsets.only(top: 2, bottom: 2, left: 8),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
),
hintText: "Email",
),
),
))
],
),
Container(
margin: EdgeInsets.only(top: 25),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
flex: 1,
child: Container(
child: Icon(Icons.lock, color: Colors.white),
margin: EdgeInsets.only(right: 5, bottom: 10),
),
),
Flexible(
flex: 7,
child: SizedBox(
height: 60,
child: TextFormField(
controller: passwordController,
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
contentPadding:
const EdgeInsets.only(top: 2, bottom: 2, left: 8),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
),
hintText: "Password",
),
),
))
],
),
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FlatButton(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
child: Text(
"Forgot Password?",
style: Theme.of(context).textTheme.body1,
),
onPressed: () {},
),
],
),
),
Container(
margin: EdgeInsets.only(top: 40, left: 25, right: 10, bottom: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
child: SizedBox(
width: double.infinity,
height: 40,
child: RaisedButton(
color: Color.fromRGBO(0, 72, 128, 100),
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(18.0),
side:
BorderSide(color: Color.fromRGBO(0, 72, 128, 100))),
child: Text(
"LOGIN",
style: Theme.of(context).textTheme.button,
),
onPressed: () {
if (_formKey.currentState.validate()) {
FutureBuilder(
future:
Provider.of<AuthService>(context, listen: false)
.signInWithEmail(emailController.text,
passwordController.text),
builder:
(BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
Navigator.pushNamed(context, "/home");
} else {
_scaffoldKey.currentState.showSnackBar(SnackBar(
duration: Duration(seconds: 4),
content: Row(
children: <Widget>[
new CircularProgressIndicator(),
new Text(" Signing-In...")
],
),
));
}
},
);
// signInWithEmail("test#test.com","test123");
}
},
),
))
],
),
)
],
),
);
}
Future<String> signInWithEmail(String email, String password) async {
FirebaseUser user;
try {
AuthResult result = await _auth.signInWithEmailAndPassword(
email: email, password: password);
user = result.user;
if (user != null) {
print("SIgn in success: " + user.email);
} else {
print("sign in failed");
}
} catch (e) {
print(e.toString());
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
void dispose() {
emailController.dispose();
passwordController.dispose();
super.dispose();
}
}
hERE when the button is pressed i CAN see the user is signed in, but I cant see the CircularProgress or I am not directed to the home page.
Why is this?
Try the following:
FutureBuilder(
future:
Provider.of<AuthService>(context, listen: false)
.signInWithEmail(emailController.text,
passwordController.text),
builder:
(BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
Navigator.pushNamed(context, "/home");
} else {
_scaffoldKey.currentState.showSnackBar(SnackBar(
duration: Duration(seconds: 4),
content: Row(
children: <Widget>[
new CircularProgressIndicator(),
new Text(" Signing-In...")
],
),
));
}
return new CircularProgressIndicator();
},
);
outside the if else add return new CircularProgressIndicator, this should show the circular indicator at the beginning and then when the future is done it will enter the if
Related
class SearchBar extends SearchDelegate {
final TumUrunlerDeneme _tumUrunlerDeneme = TumUrunlerDeneme();
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
onPressed: () {
query = '';
},
icon: const Icon(Icons.close))
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: const Icon(Icons.arrow_back_ios),
onPressed: () {
Navigator.pop(context);
},
);
}
#override
Widget buildResults(BuildContext context) {
return FutureBuilder<List<Products>>(
future: _tumUrunlerDeneme.getuserList(query: query),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
List<Products> ?data = snapshot.data;
return ListView.builder(
shrinkWrap: true,
//physics: const NeverScrollableScrollPhysics(),
itemCount: data!.length,
itemBuilder: (context, index) {
return Column(
children: [
Flex(
direction: Axis.vertical,
children:[ SingleChildScrollView(
scrollDirection: Axis.vertical,
child: GestureDetector(
onTap: () {
Get.toNamed(RouteHelper.getAllProduct(index));
},
child: Container(
margin: EdgeInsets.only(
left: Dimensions.width20,
right: Dimensions.width10,
bottom: Dimensions.height15),
child: Row(
children: [
//image section
Container(
width: Dimensions.listViewImgSize,
height: Dimensions.listViewImgSize,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(
Dimensions.radius20),
color: Colors.white38,
image: DecorationImage(
fit: BoxFit.cover,
image: CachedNetworkImageProvider(
AppConstans.BASE_URL +
AppConstans.UPLOAD_URL +
data[index]
.img!))),
),
//text section
Expanded(
child: Container(
height: Dimensions.listViewTextContSize,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topRight: Radius.circular(
Dimensions.radius20),
bottomRight: Radius.circular(
Dimensions.radius20)),
color: Colors.white),
child: Padding(
padding: EdgeInsets.only(
left: Dimensions.width10,
right: Dimensions.width10),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
BigText(
text: data[index].name!,
),
SizedBox(
height: Dimensions.height10,
),
ExpandableProductText(
text: data[index]
.description!),
SizedBox(
height: Dimensions.height10,
),
],
),
),
),
)
],
)),
),
),
]),
],
);
});
});
}
#override
Widget buildSuggestions(BuildContext context) {
return const Center(
child: Text('Ürün Arama'),
);
}
}
Here is detail page :
class AllProductDetail extends StatelessWidget {
final int pageId;
const AllProductDetail({Key? key, required this.pageId}) : super(key: key);
#override
Widget build(BuildContext context) {
var product = Get.find<TumUrunlerController>().tumUrunlerList[pageId];
return Scaffold(
backgroundColor: Colors.white,
body: CustomScrollView(
slivers: [
SliverAppBar(
automaticallyImplyLeading: false,
toolbarHeight: 70,
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(onTap: (){
Navigator.of(context).pop(context);
}
,child: const AppIcon(icon: Icons.arrow_back_ios),
),
],
),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(20),
child: Container(
child: Center(
child: BigText(
text: product.name!,
size: Dimensions.font20,
)),
width: double.maxFinite,
padding: const EdgeInsets.only(top: 0, bottom: 0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(Dimensions.radius20),
topRight: Radius.circular(Dimensions.radius20))),
),
),
backgroundColor: Colors.white,
pinned: true,
expandedHeight: Dimensions.imgsize,
flexibleSpace: FlexibleSpaceBar(
background: Image.network(
AppConstans.BASE_URL+AppConstans.UPLOAD_URL+product.img!,
width: double.maxFinite,
fit: BoxFit.fitWidth,
),
),
),
SliverToBoxAdapter(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: ExpandableText(
text: product.description!
),
margin: EdgeInsets.only(
left: Dimensions.width20, right: Dimensions.width20),
),
],
),
)
],
),
);
}
}
here is Controller page:
class TumUrunlerDeneme {
late var data = [];
List<Products> results= [];
String urlList = 'http://mzpdata.com/api/v1/products/allproduct';
Future<List<Products>> getuserList({String? query}) async {
var url = Uri.parse("http://mzpdata.com/api/v1/products/allproduct");
print("got TumUrunlerDeneme 1");
try {
http.Response response = await http.get(url);
if (response.statusCode == 200) {
print("got TumUrunlerDeneme 2");
data = json.decode(response.body)['products'];
print("got TumUrunlerDeneme 3");
results = data.map((e) => Products.fromJson(e)).toList();
print("got TumUrunlerDeneme 4");
if (query != null) {
results = results
.where((element) =>
element.name!.toLowerCase().contains((query.toLowerCase())))
.toList();
print("got TumUrunlerDeneme 5");
}
} else {
print("fetch error");
}
} on Exception catch (e) {
print('error: $e');
}
return results;
}
}
No matter what I search for, the detail opens according to the product order in the whole list.
When I click on the product I am looking for, I reach the details of another product.
How can I search for the product I want and find the details of the product I am looking for?
I appreciate your help.
I want the dialog to open when a button is clicked, but an error occurs due to BLoC. Previously, there was such an error with the class itself, but I successfully solved it, and in this case, the complexity already arises. I've already tried a couple of options but couldn't solve it. I tried to make the event in onPressed as a separate widget, and the same error did not work either.
home_page
class HomePage extends StatelessWidget {
final todoRepository = TodoRepository();
#override
Widget build(BuildContext context) {
// final TodoBloc todoBloc = context.read<TodoBloc>();
return BlocProvider<TodoBloc>(
create: (context) => TodoBloc(todoRepository),
child: Scaffold(
appBar: AppBar(
title: const Text('Flutter Todos'),
),
// floatingActionButton: FloatingActionButton(
// onPressed: () {
// // _addTodo(context);
// final newTodo = Todo(description: 'Todo 1');
// BlocProvider.of<TodoBloc>(context).add(CreateTodos(newTodo));
// },
// child: const Icon(Icons.add),
// ),
body: SingleChildScrollView(
child: Column(
// crossAxisAlignment: CrossAxisAlignment.center,
children: [
// ActionButton(),
TodoList(),
],
),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add, size: 32, color: Colors.black),
onPressed: () {
// showAddTodoSheet(context);
// showAddTodoSheet(BuildContext context) {
final TodoBloc todoBloc = context.read<TodoBloc>();
final _todoDescriptionFromController = TextEditingController();
showModalBottomSheet(
context: context,
builder: (builder) {
return BlocBuilder<TodoBloc, TodoState>(
builder: (context, state) {
return Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: Container(
color: Colors.transparent,
child: Container(
height: 230,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0),
topRight: Radius.circular(10.0))),
child: Padding(
padding: const EdgeInsets.only(
left: 15, top: 25.0, right: 15, bottom: 30),
child: ListView(
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextFormField(
controller:
_todoDescriptionFromController,
textInputAction:
TextInputAction.newline,
maxLines: 4,
style: const TextStyle(
fontSize: 21,
fontWeight: FontWeight.w400),
autofocus: true,
decoration: const InputDecoration(
hintText: 'I have to...',
labelText: 'New Todo',
labelStyle: TextStyle(
color: Colors.indigoAccent,
fontWeight: FontWeight.w500)),
validator: (value) {
if (value!.isEmpty) {
return 'Empty description!';
}
return value.contains('')
? 'Do not use the # char.'
: null;
},
),
),
Padding(
padding: const EdgeInsets.only(
left: 5, top: 15),
child: CircleAvatar(
backgroundColor: Colors.indigoAccent,
radius: 18,
child: IconButton(
icon: const Icon(
Icons.save,
size: 22,
color: Colors.white,
),
onPressed: () {
final newTodo = Todo(
description:
_todoDescriptionFromController
.value.text);
if (newTodo
.description.isNotEmpty) {
todoBloc
.add(CreateTodos(newTodo));
Navigator.pop(context);
}
},
),
),
)
],
),
],
),
),
),
),
);
});
});
},
),
));
}
You have to use MultiBlocProvider before MaterialApp.
just do like that
#override
Widget build(BuildContext context) => MultiBlocProvider(
providers: [
BlocProvider(create: (_) => TodoBloc()),
],
child: MaterialApp()
);
I have two widgets which I shared codes below, In first card widget for user selecting ingredients, second card will be used for displaying selected ingrediens, initial both screen will be empty, when user add an igredients both widget will be rebuilt by according to selected ingredients, I could handle it displaying in first widget, but I can not handle to display selectedIngredient list data when it changes, I know I have to use provider packages but I could not implement for my code, I have stuck please help me.. .
class AddIngredientsCard extends StatefulWidget {
AddIngredientsCard({this.subCategoryId,this.subCategoryCardId});
final int subCategoryCardId;
final int subCategoryId;
#override
_AddIngredientsCardState createState() => _AddIngredientsCardState();
}
class _AddIngredientsCardState extends State<AddIngredientsCard>{
String textValue;
double _animatedContainerHeight=350;
double _top=15;
double _right=30;
double _left=30;
double _bottom=15;
List<String> items= [];
List<String>selectedIngredients=[];
#override
void initState() {
ingredients=ingredients..sort((String a, String b)=>a.compareTo(b));
items.addAll(ingredients);
super.initState();
}
void filterSearchResults(String query) {
List<String> searchList = [];
searchList.addAll(ingredients);
if(query.isNotEmpty) {
List<String> listData = [];
searchList.forEach((item) {
if(item.contains(query)) {
listData.add(item);
}
});
setState(() {
items.clear();
items.addAll(listData);
});
return;
} else {
setState(() {
items.clear();
items.addAll(ingredients);
});
}
}
void _toggleCardSize(){
_top==15?_top=7.5: _top=15;
_right==30?_right=7.5: _right=30;
_left==30?_left=7.5: _left=30;
_bottom==15?_bottom=7.5: _bottom=15;
}
void _toggleCardHeight(){
_animatedContainerHeight==350?_animatedContainerHeight=600:_animatedContainerHeight=350;
}
#override
Widget build(BuildContext context) {
return AnimatedPadding(
duration: Duration(milliseconds: 500),
curve: Curves.linearToEaseOut,
padding:EdgeInsets.only(top: _top,right: _right,left: _left,bottom: _bottom),
child: AnimatedContainer(
height:_animatedContainerHeight,
duration: Duration(milliseconds: 500),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
border:Border.all(style: BorderStyle.solid, width: 1),
color: Colors.white,
borderRadius: BorderRadius.circular(90),
),
height: 60,
child: TextField(
style: TextStyle(
color: Colors.black,
fontFamily:"OpenSans",
fontSize: 20,
),
textAlign: TextAlign.center,
textAlignVertical: TextAlignVertical.center,
onChanged: (value){
if(value.length>0){
value=value[0].toUpperCase()+value.substring(1);
filterSearchResults(value);
}
else{
filterSearchResults(value);
}
},
decoration: InputDecoration(
prefixIcon: Icon(Icons.search),
border:OutlineInputBorder(
borderRadius: BorderRadius.circular(90),
borderSide: BorderSide(
color: kColorTheme10,
),
),
hintText: "Malzeme ismi arayın",
hintStyle: TextStyle(
color: Colors.black.withOpacity(0.5),
fontFamily: "OpenSans",
),
),
),
),
SizedBox(height: 2,),
Expanded(
flex: _animatedContainerHeight==350?1:4,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: selectedIngredients.length,
itemBuilder: (context,index){
return Padding(
padding: EdgeInsets.all(1),
child: GestureDetector(
onTap: (){
setState(() {
selectedIngredients.removeAt(index);
if (selectedIngredients.length == 0) {
_toggleCardHeight();
_toggleCardSize();
}
}
);
},
child: Container(
decoration: BoxDecoration(
color: kColorTheme11,
borderRadius: BorderRadius.circular(90),
border: Border.all(style: BorderStyle.solid,width: 1),
),
child: Padding(
padding: EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
BorderedText(strokeColor: Colors.black,strokeWidth: 5,child: Text(selectedIngredients[index],style:
TextStyle(fontWeight: FontWeight.bold,fontSize:20,color: Colors.white),)),
SizedBox(width: 5,),
Icon(
Icons.cancel,color: Colors.white,size: 20,
),
],
),
),
),
),
);
}
),
),
SizedBox(height: 2,),
Expanded(
flex: 40,
child: ListView.builder(
shrinkWrap: true,
itemCount: items.length,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.all(2.0),
child: GestureDetector(
onTap: (){
setState(() {
if(selectedIngredients.length==0){
selectedIngredients.add("${items[index]}");
_toggleCardHeight();
_toggleCardSize();
}
else{
selectedIngredients.add("${items[index]}");
}
});
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(90),
border: Border.all(style:BorderStyle.solid,width: 1),
color: Colors.white54,
),
child: Padding(
padding: EdgeInsets.all(5),
child: Text('${items[index]}',style: TextStyle(fontWeight: FontWeight.bold),)),
),
),
);
},
),
),
SizedBox(height: 8,),
Expanded(
flex: _animatedContainerHeight==350?1:4,
child: Row(
children: [
Expanded(
child: Container(
decoration: BoxDecoration(
color: _animatedContainerHeight==350?categoryModels[widget.subCategoryId].
subCategoryModels[widget.subCategoryCardId].categoryColor.withOpacity(0.1):kColorTheme11,
borderRadius: BorderRadius.circular(20),
border: _animatedContainerHeight==350?null:
Border.all(style: BorderStyle.solid,width: 2),
),
child: Padding(
padding: EdgeInsets.all(5),
child: GestureDetector(
onTap: (){
AddIngredientsAmount(subCategoryId:widget.subCategoryId,subCategoryCardId: widget.subCategoryId,selectedIngredients: selectedIngredients,);
/////////////////////////////////////// => isPageSaved için Provider eklenecek...
},
child: Center(child: BorderedText(strokeWidth:3,strokeColor: Colors.black,child:
Text("KAYDET",style: TextStyle(fontSize: 25, fontWeight: FontWeight.w900 ,color: Colors.white))),
),
),
),
)
),
],
),
),
],
),
),
decoration: BoxDecoration(
border: Border.all(style: BorderStyle.solid, width: 1),
borderRadius: BorderRadius.circular(30),
color:categoryModels[widget.subCategoryId].subCategoryModels[widget.subCategoryCardId].categoryColor.withOpacity(0.5),
)
),
);
}
}
class AddIngredientsAmount extends StatefulWidget {
AddIngredientsAmount({this.subCategoryId,this.subCategoryCardId, this.selectedIngredients});
final List selectedIngredients;
final int subCategoryCardId;
final int subCategoryId;
#override
_AddIngredientsAmountState createState() => _AddIngredientsAmountState();
}
class _AddIngredientsAmountState extends State<AddIngredientsAmount> {
String textValue;
double _animatedContainerHeight=300;
double _top=15;
double _right=30;
double _left=30;
double _bottom=15;
#override
Widget build(BuildContext context) {
void _toggleCardSize(){
_top==15?_top=7.5: _top=15;
_right==30?_right=7.5: _right=30;
_left==30?_left=7.5: _left=30;
_bottom==15?_bottom=7.5: _bottom=15;
}
void _toggleCardHeight(){
_animatedContainerHeight==300?_animatedContainerHeight=500:_animatedContainerHeight=300;
}
return AnimatedPadding(
duration: Duration(milliseconds: 500),
curve: Curves.linearToEaseOut,
padding:EdgeInsets.only(top: _top,right: _right,left: _left,bottom: _bottom),
child: GestureDetector(
onTap: (){
setState(() {
_toggleCardHeight();
_toggleCardSize();
});
},
child: AnimatedContainer(
height:_animatedContainerHeight,
duration: Duration(milliseconds: 500),
child: Padding(
padding: EdgeInsets.all(15.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
decoration: BoxDecoration(
border:Border.all(style: BorderStyle.solid, width: 1),
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(90))),
child: Center(
child: Text("Malzemelerinizin Miktarını Belirlerin",style: TextStyle(
color: Colors.black,
fontFamily:'OpenSans',
fontSize:25,
fontWeight: FontWeight.w300,
),
),
),
),
SizedBox(height: 7.5,),
Expanded(
child: Container(
decoration: BoxDecoration(
color:Colors.white,
border: Border.all(style: BorderStyle.solid, width: 1),
borderRadius: BorderRadius.circular(10),
),
child: ListView.builder(
itemCount: widget.selectedIngredients.length==null?0:
widget.selectedIngredients.length,
itemBuilder: (context, index){
return Padding(
padding: EdgeInsets.all(2),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(90),
border: Border.all(style:BorderStyle.solid,width: 1),
color: Colors.white54,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.all(5),
child: Text('${widget.selectedIngredients[index]}',style: TextStyle(fontWeight: FontWeight.bold,fontSize: 30),)),
],
),
),
);
},
),
),
),
],
),
),
decoration: BoxDecoration(
border: Border.all(style: BorderStyle.solid, width: 1),
borderRadius: BorderRadius.circular(30),
color:categoryModels[widget.subCategoryId].subCategoryModels[widget.subCategoryCardId].categoryColor.withOpacity(0.5),
)
)
),
);
}
}
//------------------------------------------------------------------------
class AddRecipeVoice extends StatefulWidget {
AddRecipeVoice({this.subCategoryId,this.subCategoryCardId});
final int subCategoryCardId;
final int subCategoryId;
#override
_AddRecipeVoiceState createState() => _AddRecipeVoiceState();
}
class _AddRecipeVoiceState extends State<AddRecipeVoice> {
String textValue;
#override
Widget build(BuildContext context) {
return AnimatedPadding(
duration: Duration(seconds: 1),
curve: Curves.linearToEaseOut,
padding:EdgeInsets.only(top: 15,left: 30,right: 30,bottom: 7.5),
child: GestureDetector(
onTap: (){
setState(() {
});
},
child: Container(
height:130,
child: Padding(
padding: EdgeInsets.all(15.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
decoration: BoxDecoration(
border:Border.all(style: BorderStyle.solid, width: 1),
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(90))),
child: Center(
child: Text("Tarifinizi anlatın",style: TextStyle(
color: Colors.black,
fontFamily:'OpenSans',
fontSize:25,
fontWeight: FontWeight.w300,
),
),
),
),
SizedBox(height: 7.5,),
Expanded(
child: GestureDetector(
child: Container(
decoration: BoxDecoration(
color:kColorTheme7,
border: Border.all(style: BorderStyle.solid, width: 1),
borderRadius: BorderRadius.circular(20),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Icon(Icons.mic,size: 40,color: Colors.white,),
SizedBox(width: 50,),
Text(
"KAYIT ZAMANI !!",
style: TextStyle(
fontSize: 30,
fontFamily: "OpenSans",
color: Colors.white,
fontWeight: FontWeight.bold
),
),
],
),
),
),
),
],
),
),
decoration: BoxDecoration(
border: Border.all(style: BorderStyle.solid, width: 1),
borderRadius: BorderRadius.circular(30),
color:categoryModels[widget.subCategoryId].subCategoryModels[widget.subCategoryCardId].categoryColor.withOpacity(0.5),
)
)
),
);
}
}
Make a provider class that mixin with ChangeNotifier.
Wrap your widget prior calling the provider class with MultiProvider widget. Likewise:
MultiProvider (
providers: [
ChangeNotifierProvider.value(value: IngredientsProvider()),
],
child: YourWidget(), //You can wrap your MaterialApp here
)
Create your needed methods that changes the selected data and call notifyListeners() inside your method. It will rebuild your desired widget where you listen to them.
Example:
class IngredientsProvider with ChangeNotifier {
List<String> _selectedIngredients = [];
List<String> get selectedIngredients() {
return _selectedIngredients;
}
void addIngredient(String ingredient) {
_selectedIngredients.add(ingredient);
notifyListeners();
}
}
In your widget listen to them:
Widget1 {
//Call this in you onPress/onTap
void addIngredient(String ing, BuildContext ctx) {
Provider.of<IngredientsProvider>(ctx, listen:
false).addIngredient(ing);
}
........
#override
Widget build(BuildContext context) {
//Use this list to select
List<String> _ingredients = Provider.of<IngredientsProvider>(context, listen:
true).ingredients;
}
........
}
Use in the 2nd Widget in this way.
Widget2 {
........
#override
Widget build(BuildContext context) {
//Use this list to show
List<String> _ingredients = Provider.of<IngredientsProvider>(context, listen:
true).ingredients;
}
........
}
I have seen many same questions but they don't have answers yet, so I decided to put it again.
I am using rest API to load data in Gridview.count with ScrollController which is generally working fine but many times some images are not loading on the frame and i got this error:-
"Connection closed before full header was received, uri =IMAGE URL"
Here is my code
class CreateHome extends StatefulWidget {
_AppState state;
BuildContext context;
CreateHome(this.state, this.context);
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return new CreateHomeState(state, context);
}
}
class CreateHomeState extends State<CreateHome> {
_AppState state;
BuildContext context;
int _selectBuilder = 0;
List<ProductModel> productList = new List();
CreateHomeState(this.state, this.context);
ScrollController _controller;
String lasthit = "";
FutureBuilder<List<ProductModel>> _getFutureBuilder(int pos) {
switch (pos) {
case 0:
return new FutureBuilder(
future: Api.getProductList(context, '0'),
builder: (context, snapshot) {
if (snapshot.hasData) {
productList.addAll(snapshot.data);
return GridList(productList);
} else if (snapshot.hasError) {
Toast.show(snapshot.error, context,
duration: 3, backgroundColor: Colors.deepOrange);
}
return RoundProgress();
},
);
case 1:
return new FutureBuilder(
future: Api.getProductList(
context, productList[productList.length - 1].product_id),
builder: (context, snapshot) {
lasthit = productList[productList.length - 1].product_id;
if (snapshot.hasData) {
productList.addAll(snapshot.data);
//productList = productList.sublist(productList.length-7, productList.length-1);
var distinctIds = productList.toSet().toList();
return GridList(distinctIds);
} else if (snapshot.hasError) {
Toast.show(snapshot.error, context,
duration: 3, backgroundColor: Colors.deepOrange);
}
return RoundProgress();
},
);
}
}
#override
void initState() {
print('initstatecalled');
_controller = ScrollController();
_controller.addListener(_scrollListener);
super.initState();
}
_scrollListener() {
if (_controller.offset >= _controller.position.maxScrollExtent &&
!_controller.position.outOfRange) {
print(productList.length.toString());
String currentHit = productList[productList.length - 1].product_id;
if (currentHit != lasthit) {
setState(() {
_selectBuilder = 1;
});
}
}
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
controller: _controller,
child: Container(
color: Colors.black12,
//=========Main Container For Scrollview==============//
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 15, 0, 0),
child: Column(
children: <Widget>[
Container(
width: double.infinity,
//================Container for Categories==================//
color: Colors.white,
child: Container(
height: 130,
child: FutureBuilder<List<CategoryModel>>(
future: Api.getDataCategories(context),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<CategoryModel> categoryListing = snapshot.data;
return ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: categoryListing.length,
itemBuilder: (BuildContext context, int index) {
return createList(
state,
categoryListing[index].url,
categoryListing[index].name,
1,
categoryListing[index].id);
},
);
} else if (snapshot.hasError) {
Toast.show("Error", context,
duration: 3,
gravity: Toast.BOTTOM,
backgroundColor: Colors.deepOrange);
}
return RoundProgress();
},
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 20, 0, 20),
child: Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
child: SizedBox(
child: FutureBuilder<List<String>>(
future: Api.getBanners(context, "front"),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<String> images = snapshot.data;
return CarouselWithIndicator(images);
} else if (snapshot.hasError) {
Toast.show("Error", context,
duration: 3,
gravity: Toast.BOTTOM,
backgroundColor: Colors.deepOrange);
}
return RoundProgress();
},
),
),
),
),
),
Container(
color: Colors.white, child: _getFutureBuilder(_selectBuilder))
],
),
),
),
);
}
}
This is my code for making GridView
class GridList extends StatelessWidget {
List<ProductModel> list;
GridList(this.list);
#override
Widget build(BuildContext context) {
print('length from grid..'+list.length.toString());
IconData icon;
Color color;
String price;
bool boolean;
return Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Text(
'Popular Products',
style: TextStyle(
fontSize: 16,
fontFamily: 'SFProRegular',
color: Colors.black),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
child: GridView.count(
shrinkWrap: true,
primary: false,
childAspectRatio: 0.6,
//(itemWidth / itemHeight),
crossAxisCount: 2,
children: List.generate(list.length, (index) {
if (list[index].wishlist == "1") {
icon = Icons.favorite;
color = Colors.red;
} else {
icon = Icons.favorite_border;
color = Colors.black38;
}
if (list[index].discounted_price != "0") {
price = "Rs " + list[index].discounted_price;
boolean = true;
} else {
price = "Rs " + list[index].price;
boolean = false;
}
return Wrap(
children: <Widget>[
Card(
elevation: 5,
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
constraints: new BoxConstraints.expand(
height: 150.0,
),
padding:
new EdgeInsets.only(top: 8.0, right: 8.0),
decoration: new BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(4),
topRight: Radius.circular(4)),
image: new DecorationImage(
image:
new NetworkImage(list[index].image_url),
fit: BoxFit.cover,
),
),
child: new Stack(
children: <Widget>[
new Positioned(
right: 0.0,
top: 0.0,
child: Material(
borderRadius: BorderRadius.all(
Radius.circular(50)),
child: Padding(
padding: const EdgeInsets.all(6.0),
child: Center(
child: new Icon(
icon,
color: color,
size: 16,
),
),
),
),
),
],
)),
Padding(
padding:
const EdgeInsets.fromLTRB(5.0, 10, 0, 10),
child: Text(
list[index].product_name,
style: TextStyle(
fontSize: 16,
fontFamily: 'SFProRegular',
color: Colors.black),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(5.0, 0, 0, 10),
child: Row(
children: <Widget>[
Icon(
Icons.person,
size: 23,
color: Colors.black38,
),
Padding(
padding:
const EdgeInsets.fromLTRB(5.0, 0, 0, 0),
child: Text(
list[index].designer,
style: TextStyle(
fontSize: 14,
fontFamily: 'SFProRegular',
color: Colors.black38,
decoration: TextDecoration.underline,
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.fromLTRB(5.0, 2, 0, 10),
child: Row(
children: <Widget>[
Text(
price,
style: TextStyle(
fontSize: 13,
fontFamily: 'SFProRegular',
color: Colors.green),
),
Padding(
padding:
const EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Visibility(
visible: boolean,
maintainSize: true,
maintainAnimation: true,
maintainState: true,
child: Text(
"Rs " + list[index].price,
style: TextStyle(
fontSize: 13,
fontFamily: 'SFProRegular',
color: Colors.grey,
decoration:
TextDecoration.lineThrough),
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.fromLTRB(5.0, 0, 0, 5),
child: Visibility(
maintainSize: true,
maintainAnimation: true,
maintainState: true,
visible: boolean,
child: Text(
list[index].discount + '% OFF',
style: TextStyle(
fontSize: 13,
fontFamily: 'SFProRegular',
color: Colors.deepOrange),
),
),
),
],
),
),
),
],
);
}),
crossAxisSpacing: 3.0,
mainAxisSpacing: 5.0,
),
),
],
),
);
}
}
this issue will be solved by
Flutter Clean
run
Hi I have designed a screen in flutter. I have AlertDialog on which I want to close the dialog and screen on pressing. Right now AlertDialog dismiss on press but screen is not closing.
Does anyone know how to do this ?
class ForgotPasswordScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return ForgotPasswordScreenState();
}
}
class ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
var emailController = new TextEditingController();
var authHandler = new Auth();
bool isLoading = false;
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Container(
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
color: Colors.white,
),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Row(
children: <Widget>[
new Expanded(
child: isLoading
? Center(child: CircularProgressIndicator())
: new Container()),
],
),
new Row(
children: <Widget>[
new Expanded(
child: new Padding(
padding: const EdgeInsets.only(left: 40.0),
child: new Text(
"EMAIL",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.redAccent,
fontSize: 15.0,
),
),
),
),
],
),
new Container(
width: MediaQuery.of(context).size.width,
margin:
const EdgeInsets.only(left: 40.0, right: 40.0, top: 10.0),
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.redAccent,
width: 0.5,
style: BorderStyle.solid),
),
),
padding: const EdgeInsets.only(left: 0.0, right: 10.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Expanded(
child: TextField(
controller: emailController,
textAlign: TextAlign.left,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'PLEASE ENTER YOUR EMAIL',
hintStyle: TextStyle(color: Colors.grey),
),
),
),
],
),
),
Divider(
height: 24.0,
),
new Container(
width: MediaQuery.of(context).size.width,
margin:
const EdgeInsets.only(left: 30.0, right: 30.0, top: 20.0),
alignment: Alignment.center,
child: new Row(
children: <Widget>[
new Expanded(
child: new FlatButton(
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0),
),
color: Colors.redAccent,
onPressed: () {
setState(() {
isLoading = true;
});
authHandler
.sendPasswordResetEmail(emailController.text)
.then((void nothing) {
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
content: new Text(
"Password reset email has been sent."),
actions: <Widget>[
// usually buttons at the bottom of the dialog
new FlatButton(
child: new Text("OK"),
onPressed: () {
Navigator.pop(context);
},
),
],
);
},
);
setState(() {
isLoading = false;
});
}).catchError((e) => print(e));
},
child: new Container(
padding: const EdgeInsets.symmetric(
vertical: 20.0,
horizontal: 20.0,
),
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Expanded(
child: Text(
"FORGOT PASSWORD",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold),
),
),
],
),
),
),
),
],
),
),
],
)));
}
}
Ideally, you'll want to call pop more than once. One for the modal, another for the actual route.
There are a few ways to achieve this. But ideally you'll want to await the close of the dialog before triggering another close:
foo() async {
await showDialog(
context: context,
builder: (context) => AlertDialog(
actions: [
new FlatButton(
child: new Text("OK"),
onPressed: () => Navigator.pop(context),
),
],
),
);
Navigator.pop(context);
}
This way, both the route and the modal can handle their close however they like.
This is how i did with mine
bool _logout = false;
and then at the start of build Widget
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
_onBackPressed(context);
return _logout;
},
child: Container(),
);
}
and the method _onBackPressed returns a custom dialog Class like so
void _onBackPressed(BuildContext c) async {
await showDialog(
barrierColor: CustomColors.darkGrey.withOpacity(0.8),
barrierDismissible: true,
context: context,
builder: (BuildContext context) {
return CustomDialogBox(
title: 'Logout',
description: 'Are you sure you want to logout?',
rightButtonText: 'Yes',
onPClick: () {
_logout = true;
if (_logout == true) {
Get.back();
}
},
onNClick: () {
_logout = false;
Get.back();
},
);
});
if (_logout == true) {
Get.back();
}
}
and my custom Dialog class is here
class CustomDialogBox extends StatefulWidget {
final String? title, description, leftButtonText, rightButtonText;
final VoidCallback? onPClick, onNClick;
final Image? image;
const CustomDialogBox({
Key? key,
this.title,
this.description,
this.leftButtonText,
this.rightButtonText,
this.image,
this.onPClick,
this.onNClick,
}) : super(key: key);
#override
_CustomDialogBoxState createState() =>
// ignore: no_logic_in_create_state
_CustomDialogBoxState(onPClick!, onNClick!);
}
class _CustomDialogBoxState extends State<CustomDialogBox> {
final VoidCallback onPClick, onNClick;
_CustomDialogBoxState(this.onPClick, this.onNClick);
#override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(Dimensions.BORDER_RADIUS_4),
),
elevation: 0,
backgroundColor: Colors.transparent,
child: Container(
//height: 200,
padding: const EdgeInsets.only(
left: 10,
right: 0,
bottom: 10,
),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.white,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: CustomColors.darkGrey,
offset: const Offset(0, 30),
blurRadius: 20,
),
]),
child: Wrap(children: <Widget>[
dialogBody(context),
]),
),
);
}
Widget dialogBody(context) {
return Column(children: [
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Image.asset(
Images.LOGO,
height: MediaQuery.of(context).size.height * 0.035,
),
IconButton(
//padding: const EdgeInsets.all(0),
onPressed: () {
Get.back();
},
icon: const CircleAvatar(
radius: 12.5,
child: Icon(
Icons.close,
color: Colors.white,
),
backgroundColor: Colors.red,
),
),
]),
Padding(
padding: const EdgeInsets.only(
right: 10,
),
child: Column(children: [
//----//
customText(
text: widget.title ?? '',
fontFamily: 'black',
fontSize: 16,
),
//----//
const Space(0, 0.01),
//----//
customText(
text: widget.description ?? '',
fontSize: 14,
),
]),
),
//----//
const Space(0, 0.03),
//----//
Padding(
padding: const EdgeInsets.only(
right: 10,
),
child:
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
//----//
raisedButton(
text: widget.leftButtonText ?? 'Cancel',
fontFamily: 'roman',
height: 35,
width: 105,
buttonColor: CustomColors.red,
onClick: () {
return onNClick();
},
context: context,
),
//----//
raisedButton(
text: widget.rightButtonText ?? 'Okay',
fontFamily: 'roman',
height: 35,
width: 105,
buttonColor: CustomColors.green,
onClick: () {
return onPClick();
},
context: context,
),
//----//
]),
),
]);
}
}
the buttons and texts are custom so feel free to change them. and where you see Get.back(); is GetX code.. you can replace with Navigator.of(context).pop();
try this
showPop() async {
await showDialog(
context: context,
barrierDismissible: true,
builder: (context) => AlertDialog(
actions: [
new FlatButton(
child: new Text("Close"),
onPressed: () => Navigator.pop(context),
),
],
),
);
}