Related
I'm making a food ordering app in which I want to provide a discount feature. I've implemented most of the part but I'm getting stuck at a point where I basically want to update the totalAmount with the discountRate.
class CartScreen extends StatefulWidget
{
final String? sellerUID;
const CartScreen({super.key, this.sellerUID});
#override
_CartScreenState createState() => _CartScreenState();
}
class _CartScreenState extends State<CartScreen>
{
List<int>? separateItemQuantityList;
num totalAmount = 0;
final _couponText = TextEditingController();
#override
void initState() {
super.initState();
totalAmount = 0;
Provider.of<TotalAmount>(context, listen: false).displayTotalAmount(0);
separateItemQuantityList = separateItemQuantities();
}
#override
Widget build(BuildContext context) {
var _coupon = Provider.of<CouponProvider>(context);
double discountRate = _coupon.discount/100;
return Scaffold(
appBar: AppBar(
title: const Text("Cart"),
flexibleSpace: Container(decoration: BoxDecoration(color: myColor),),
automaticallyImplyLeading: true,
),
body: CustomScrollView(
slivers: [
//display cart items with quantity number
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("items")
.where("itemID", whereIn: separateItemIDs())
.orderBy("publishedDate", descending: true)
.snapshots(),
builder: (context, snapshot)
{
return !snapshot.hasData
? SliverToBoxAdapter(child: Center(child: circularProgress(),),)
: snapshot.data!.docs.isEmpty
? const SliverToBoxAdapter(child: Center(child: Padding(
padding: EdgeInsets.only(top: 300),
child: Text("The cart is empty",style: TextStyle(
fontSize: 24, fontWeight: FontWeight.bold),),
)))
: SliverList(
delegate: SliverChildBuilderDelegate((context, index)
{
Items model = Items.fromJson(
snapshot.data!.docs[index].data()! as Map<String, dynamic>,
);
if(index == 0)
{
totalAmount = 0;
totalAmount = totalAmount + (model.price! * separateItemQuantityList![index]);
}
else
{
totalAmount = totalAmount + (model.price! * separateItemQuantityList![index]);
}
if(snapshot.data!.docs.length - 1 == index)
{
WidgetsBinding.instance.addPostFrameCallback((timeStamp)
{
Provider.of<TotalAmount>(context, listen: false).displayTotalAmount(totalAmount.toDouble());
});
}
return CartItemDesign(
model: model,
context: context,
quanNumber: separateItemQuantityList![index],
);
},
childCount: snapshot.hasData ? snapshot.data!.docs.length : 0,
),
);
},
),
SliverFillRemaining(
hasScrollBody: false,
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
decoration: BoxDecoration(
color: const Color(0xfffb9e5a).withOpacity(0.6),
borderRadius: const BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)),
),
width: double.infinity,
height: 160,
child: Padding(
padding: const EdgeInsets.fromLTRB(8, 12, 8, 6),
child: Column(
children: [
Consumer2<TotalAmount, CartItemCounter>(builder: (context, amountProvider, cartProvider, c){
return Center(
child: cartProvider.count == 0
? const Text("Please add something in the cart", style: TextStyle(fontSize: 18),)
: Column(
children: [
Text("The total amount is ₹${amountProvider.tAmount.toString()}", style: const TextStyle(fontSize: 18)),
const SizedBox(height: 10,),
Container(
height: 50,
width: MediaQuery.of(context).size.width * 8,
decoration: BoxDecoration(
border: Border.all(color: myColor, width: 1,),
borderRadius: const BorderRadius.all(Radius.circular(20)),
color: Colors.white54
//color: Colors.white54
),
child: Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 10, right: 15),
child: TextField(
controller: _couponText,
maxLines: 1,
decoration: const InputDecoration.collapsed(
hintText: 'Apply coupon here ...'
),
),
),
),
Padding(
padding: const EdgeInsets.only(right: 10),
child: ElevatedButton(
onPressed: (){
_coupon.getcouponDetails(_couponText.text).then((value) {
if(value.data() == null){
setState(() {
_coupon.discount = 0;
});
showCodeDialog(_couponText.text, 'not valid');
return;
}
if(_coupon.expired==false){
// Code to be done here.
Fluttertoast.showToast(msg: 'Coupon is valid');
// I want to update the totalAmount value with the discountRate here...
}
if(_coupon.expired==true){
setState(() {
_coupon.discount = 0;
});
showCodeDialog(_couponText.text, 'expired');
return;
}
});
},
style: ElevatedButton.styleFrom(
textStyle: const TextStyle(
fontSize: 15,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
)
),
child: const Text('Apply'),
),
),
],
),
),
const SizedBox(height: 10,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton.icon(
onPressed: (){
clearCartNow(context);
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (c) => const HomeScreen()));
Fluttertoast.showToast(msg: "Cart cleared");
},
style: ElevatedButton.styleFrom(
foregroundColor: Colors.black, backgroundColor: myColor
),
icon: const Icon(Icons.clear_all),
label: const Text("Clear")),
ElevatedButton.icon(
onPressed: (){
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (c)=> AddressScreen(
totalAmount: totalAmount.toDouble(),
sellerUID: widget.sellerUID,
),
),
);
},
style: ElevatedButton.styleFrom(
foregroundColor: Colors.black,
backgroundColor: myColor,
),
icon: const Icon(Icons.navigate_next),
label: const Text("Proceed")),
],
)
],
),
);
}),
],
),
)
),
),
)
],
),
);
}
showCodeDialog(code, validity){
showCupertinoDialog(
context: context,
builder: (BuildContext context){
return CupertinoAlertDialog(
title: const Text('Apply Coupon'),
content: Text('This discount coupon $code you have entered is $validity'),
actions: [
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: (){Navigator.pop(context);},
child: Text('Ok', style: TextStyle(color: Colors.white),),
),
)
],
);
});
}
}
I tried changing the totalAmount, amountProvider.tAmount and their types, but nothing is working for me.
In this image, the total amount is without discount. If I apply a coupon of 10%, the total amount should be subtracted by 10%.
I can add more information if required.
Hey guys I'm working on some project and need to create a custom dropdown,
like this
I am able to make that here is the code, the code is messy but I will refactor it once I make it work. Or if you have some other way how I can accomplish this I'm open to suggestions.
GlobalKey? actionKey = GlobalKey();
List<String> picked = [];
List<IconData> icons = [
Icons.blur_circular_outlined,
Icons.sports_basketball,
Icons.sports_baseball_sharp,
Icons.sports_tennis_rounded,
Icons.people,
];
List<String> sports = [
"Fudbal",
"Kosarka",
"Tenis",
"Stoni tenis",
"Kuglanje"
];
List<int> ints = [0, 1, 2, 3, 4];
List<bool> booles = [false, false, false, false, false];
OverlayEntry? overlayEntry;
var position;
double? y;
double? x;
void findDropdownData() {
RenderBox renderBox =
actionKey!.currentContext!.findRenderObject() as RenderBox;
position = renderBox.localToGlobal(Offset.zero);
y = position!.dy;
x = position!.dx;
}
OverlayEntry _overlayEntryBuilder() {
return OverlayEntry(
builder: (context) {
return Positioned(
// top: position,
left: 16.w,
right: 16.w,
child: Material(
child: dropdownExpanded(),
),
);
},
);
}
Widget buildRows(i) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 17.w, vertical: 15.h),
child: Row(
children: [
SizedBox(
height: 24.h,
width: 24.w,
child: Checkbox(
activeColor: style.purpleMain,
value: booles[i],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4)),
onChanged: (value) {
setState(() {
booles[i] = value!;
booles[i] == true
? picked.add(sports[i])
: picked.remove(sports[i]);
});
},
),
),
SizedBox(
width: 10.w,
),
Text(
sports[i],
style: TextStyle(
color: booles[i] == true ? style.purpleMain : Colors.grey,
),
),
const Spacer(),
Icon(
icons[i],
color: booles[i] == true ? style.purpleMain : Colors.grey,
size: 15,
),
],
),
);
}
Widget dropdown() {
return GestureDetector(
key: actionKey,
onTap: () {
setState(() {
isPressed = !isPressed;
});
if (isPressed == false) {
overlayEntry = _overlayEntryBuilder();
Overlay.of(context)!.insert(overlayEntry!);
}
},
child: Container(
width: double.infinity,
height: 50.h,
decoration: BoxDecoration(
border: Border.all(color: style.e8e8e8),
borderRadius: BorderRadius.circular(8),
),
padding: EdgeInsets.only(left: 16.w, right: 13.w),
child: Row(
children: [
picked.isEmpty ? pickedEmpty() : pickedNotEmpty(),
const Spacer(),
const Icon(
Icons.arrow_drop_down,
color: style.bdbdbd,
),
],
),
),
);
}
Widget pickedEmpty() {
return Text(
"Možete obeležiti više aktivnosti",
style: TextStyle(
fontSize: 16.sp,
color: style.bdbdbd,
fontWeight: FontWeight.w400,
),
);
}
Widget pickedNotEmpty() {
List<Widget> list = <Widget>[];
for (var i = 0; i < picked.length; i++) {
list.add(
Padding(
padding: EdgeInsets.only(right: 5.w),
child: Text(
picked[i],
style: TextStyle(
fontSize: 16.sp,
color: style.bdbdbd,
fontWeight: FontWeight.w400,
),
),
),
);
}
return Row(children: list);
}
Widget dropdownExpanded() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: style.purpleMain),
borderRadius: BorderRadius.circular(8),
),
child: Column(
children: [
GestureDetector(
onTap: () {
setState(() {
isPressed = !isPressed;
});
overlayEntry?.remove();
},
child: Container(
width: double.infinity,
height: 50.h,
padding: EdgeInsets.only(left: 16.w, right: 13.w),
child: Row(
children: [
picked.isEmpty ? pickedEmpty() : pickedNotEmpty(),
const Spacer(),
const Icon(
Icons.arrow_drop_up,
color: style.bdbdbd,
),
],
),
),
),
const Divider(
height: 0,
thickness: 1,
color: style.e8e8e8,
indent: 17,
endIndent: 17,
),
Column(
children: [
for (int i in ints) buildRows(i),
],
),
],
),
);
}
Here are results
This is what I want to accomplish
So I just want to move down this expanded dropdown and how to update these booles in the overlay if I don't use overlay it's working as it should but I need to open that dropdown on the top of another content. Thanks for the help.
Use smart_select it is fully customizable and you can achieve the design you want easily using this library.
Updated Answer
Regarding the UI, it is like an Expansions Tile Widget in flutter. You can implement that dropdown with expansions tile and pass list of items in children,
for expand, collapse tile after select each item, you can create a global key and control that in UI.
final GlobalKey<AppExpansionTileState> expansionTile = new GlobalKey();
collapse → expansionTile.currentState.collapse();
ExpansionTile(
title: Text(
"Možete obeležiti više aktivnosti",
style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w500),
),
children: <Widget>[
// put items here
],
),
smaple :
Widget customDropDown() => Container(
// color: Colors.white,
padding: const EdgeInsets.all(10),
child: ListTileTheme(
dense: true,
child: ExpansionTile(
title: const Text(
"Možete obeležiti više aktivnosti",
style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w500),
),
children: <Widget>[
Container(
width: double.infinity,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius.vertical(bottom: Radius.circular(20))),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: const [
ListTile(
leading: Icon(Icons.ac_unit),
title: Text("something"),
),
ListTile(
leading: Icon(Icons.ac_unit),
title: Text("something"),
),
ListTile(
leading: Icon(Icons.ac_unit),
title: Text("something"),
),
ListTile(
leading: Icon(Icons.ac_unit),
title: Text("something"),
)
],
),
),
)
],
),
),
);
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: SafeArea(
child: Stack(
children: [pageDesign(), customDropDown()],
),
),
),
);
}
fakeWidget(color) => Container(
height: 100,
width: double.infinity,
color: color,
child: const Center(
child: Text("widget1"),
),
);
Widget pageDesign() => Column(
children: [
/* you should control this size in diffrent orientation and for big size
device to handle responsive
*/
const SizedBox(
height: 80,
),
fakeWidget(
Colors.green,
),
fakeWidget(
Colors.yellow,
),
fakeWidget(
Colors.orange,
),
fakeWidget(
Colors.blue,
),
],
);
I used two buttons which make same thing on subcategories screen. On of them in buttom of the screen, other one stays in subcategories part (Empty Card )of the screen, from the bottom button I can add new subcategory but when I pushed to the EmptyCard to add subcategory, adding screen is oppening but when I try to push add button, I took invalid argument(s) error, Can someone help me..
class CategoryModel{
CategoryModel({this.categoryId,this.categoryImagePath,this.categoryName,this.categoryColor,this.subCategory});
final int categoryId;
final SubCategoryModel subCategory;
final Color categoryColor;
final String categoryImagePath;
final String categoryName;
final List<SubCategoryModel> subCategoryModels=[SubCategoryModel(subCategoryId: null)];
}
class SubCategoryModel{
SubCategoryModel({this.subCategoryId,this.subCategoryImagePath,this.subCategoryName, this.categoryColor});
final int subCategoryId;
final Color categoryColor;
final subCategoryImagePath;
final subCategoryName;
class EmptyCard extends StatelessWidget {
EmptyCard({this.where});
final String where;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(top:15.0),
child: TextButton(
onPressed: (){
if(where=="homeScreen"){
showModalBottomSheet(
context: context,
builder: (BuildContext context)=> AddMenuScreen(buttonText: "Menü Ekle",route:where),
);
}
else if(where=="subCategoryScreen"){
showModalBottomSheet(
context: context,
builder: (BuildContext context)=> AddMenuScreen(buttonText: "Tarif Ekle",route:where),
);
}
},
child: Container(
height: 180,
width: 180,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.black12.withOpacity(0.1),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(Icons.add_circle_outline_outlined,size: 100,color: Colors.grey.shade400,),
],
),
),
),
);
}
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
centerTitle: true,
title: BorderedText(
child:Text(
categoryModels[widget.categoryId].categoryName,
style: TextStyle(
color: Color(0XFFFFFB00),
fontSize: 30,
fontFamily: "Graduate"
),
),
strokeWidth: 5,
strokeColor: Colors.black,
),
elevation: 5,
backgroundColor: Color(0xFFF2C3D4).withOpacity(1),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: (){
Navigator.pop(context);
},
iconSize: 40,
color: Color(0xFFA2000B),
),
actions: [
CircleAvatar(
radius: 27,
backgroundColor: Colors.transparent,
backgroundImage: AssetImage("images/cuttedlogo.PNG"),
)
],
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("images/logoBGopacity.png"),
fit: BoxFit.cover,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: GridView.builder(
scrollDirection: Axis.vertical,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount:categoryModels[widget.categoryId].subCategoryModels.length,
itemBuilder: (context,index){
if(categoryModels[widget.categoryId].subCategoryModels[index].subCategoryId==null){
return EmptyCard(where: "subCategoryScreen");
}
return SubCategoryCard(subCategoryId:widget.categoryId,subcategoryName: categoryModels[widget.categoryId].subCategoryModels[index].subCategoryName,
subCategoryImagePath: categoryModels[widget.categoryId].subCategoryModels[index].subCategoryImagePath,
subCategoryColor: categoryModels[widget.categoryId].subCategoryModels[index].categoryColor,);
}
),
),
Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: EdgeInsets.all(10),
child: Container(
decoration: BoxDecoration(
border: Border.all(style: BorderStyle.solid),
color: kColorTheme7,
borderRadius: BorderRadius.circular(40),
),
child: TextButton(
onPressed: (){
showModalBottomSheet(
context: context,
builder: (BuildContext context)=> AddMenuScreen(categoryId:widget.categoryId,buttonText: "Tarif Ekle", route:"subCategoryScreen"),
);
},
child: BorderedText(
strokeWidth: 5,
strokeColor: Colors.black,
child:Text("Tarif Ekle",style: TextStyle(
color: Colors.white,
fontFamily:'Graduate',
fontSize:30,
),
),
),
),
),
),
],
)
],
),
),
),
);
}
}
class AddMenuScreen extends StatefulWidget {
AddMenuScreen({this.categoryId,this.buttonText, this.route});
final int categoryId;
final String route;
final String buttonText;
static String id="addMenuScreen";
#override
_AddMenuScreenState createState() => _AddMenuScreenState();
}
class _AddMenuScreenState extends State<AddMenuScreen> {
final stickerList= List<String>.generate(23, (index) => "images/sticker$index");
int selectedIndex=-1;
Color _containerForStickersInactiveColor=Colors.white;
Color _containerForStickersActiveColor=Colors.black12;
String chosenImagePath;
String newCategoryName;
int addScreenImageNum;
#override
Widget build(BuildContext context) {
return Material(
child: Container(
color: kColorTheme9,
child: Container(
height: 400,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(topRight: Radius.circular(40),topLeft: Radius.circular(40)),
),
child:Padding(
padding:EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
color: kColorTheme2,
borderRadius: BorderRadius.circular(90)
),
child: TextField(
style: TextStyle(
color: Colors.black,
fontFamily:"Graduate",
fontSize: 20,
),
textAlign: TextAlign.center,
onChanged: (value){
newCategoryName=value;
},
decoration: InputDecoration(
border:OutlineInputBorder(
borderRadius: BorderRadius.circular(90),
borderSide: BorderSide(
color: Colors.teal,
),
),
hintText: "Menü ismi belirleyin",
hintStyle: TextStyle(
color: Colors.black.withOpacity(0.2),
fontFamily: "Graduate",
),
),
),
),
SizedBox(height: 20,),
Text(" Yana kadırarak menünüz icin bir resim secin",textAlign: TextAlign.center,
style: TextStyle(fontFamily: "Graduate", fontSize: 12),),
SizedBox(height: 20,),
Expanded(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: stickerList.length,
itemBuilder: (context,index){
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: index == selectedIndex ?
_containerForStickersActiveColor :
_containerForStickersInactiveColor,
),
child:TextButton(
child: Image(
image: AssetImage("images/sticker$index.png"),
),
onPressed: (){
setState(() {
selectedIndex = index;
});
},
),
);
}
),
),
SizedBox(height: 20,),
Container(
decoration: BoxDecoration(
border: Border.all(style: BorderStyle.solid),
color: kColorTheme7,
borderRadius: BorderRadius.circular(90),
),
child: TextButton(
onPressed: (){
if(widget.route=="homeScreen"){
Navigator.pop(context, ModalRoute.withName(HomeScreen.id));
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context)=>HomeScreen(newCategoryName: newCategoryName,
newCategoryImagePath: "images/sticker$selectedIndex.png")));
}
else if(widget.route=="subCategoryScreen"){
Navigator.pop(context, ModalRoute.withName(SubCategoriesScreen.id));
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context)=>SubCategoriesScreen(categoryId: widget.categoryId,subCategoryName: newCategoryName,
subCategoryImagePath:"images/sticker$selectedIndex.png" )));
}
},
child: Text(widget.buttonText, style: TextStyle(fontSize: 20, color: Colors.white,
fontFamily: "Graduate", fontWeight: FontWeight.bold),),
),
),
],
),
),
),
),
);
}
}
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),
),
],
),
);
}