How to display the JSON data fetched from API in flutter? - flutter

I want to fetch the data from API and display it in flutter app. I've been able to fetch the data and display it using ListView builder. But, the problem now I'm facing is that the scroll is not working properly in this case and I don't want to display the data in the form of Lists.
So, is there any other way where we can fetch the data and show it in the app. This is how the UI is going to look.
I'm unable to accomplish this using ListView builder or any other way as I'm very new to flutter.
This is my code which I used in another widget where I was facing the scrolling issue, to create the ListView:
#override
_AllEventsState createState() => _AllEventsState();
}
class _AllEventsState extends State<AllEvents> {
final String url =
"api-url";
List data;
#override
void initState() {
super.initState();
this.getAllEvents();
}
createRoute(id) {
print('args $id');
Navigator.pushNamed(context, '/eventdetail', arguments: id);
}
Future<String> getAllEvents() async {
var response = await http.get(
Uri.encodeFull(url),
headers: {"Accept": "application/json"},
);
setState(() {
var convertDataToJson = jsonDecode(response.body);
data = convertDataToJson["events"];
});
return "Success";
}
#override
Widget build(BuildContext context) {
ScrollController _controller = new ScrollController();
return Container(
child: ListView.builder(
physics: const AlwaysScrollableScrollPhysics(),
controller: _controller,
shrinkWrap: true,
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext cont, int index) {
// format date
var dateString = data[index]["eventDate"];
var eventDate = Jiffy(dateString).MMMEd;
return Container(
padding: const EdgeInsets.fromLTRB(30, 7, 30, 7),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new InkWell(
onTap: () {
print('card tapped');
createRoute(data[index]['_id']);
},
child: Card(
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 3,
color: hexToColor("#EBEBEB"),
),
borderRadius: BorderRadius.circular(8.0),
),
padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
customText(
eventDate.toString(),
"#000000",
"20.0",
TextAlign.left,
"Roboto Black",
FontWeight.w900,
),
customText(
"10, 9",
"#000000",
"20.0",
TextAlign.right,
"Roboto Black",
FontWeight.w900,
),
],
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: customText(
"${data[index]['city']} | ${data[index]['arenaName']} | ${data[index]['categories'][0]['title']}",
"#000000",
"18.0",
TextAlign.left,
"Roboto Black",
FontWeight.w900,
),
),
],
),
],
),
),
),
),
],
),
),
);
},
),
);
}
}
This is how I'm fetching the data from the API in another widget:
print("$url${widget.eventId}");
var response = await http.get(
Uri.encodeFull("$url${widget.eventId}"),
// headers: {"Accept": "application/json"},
);
print('events response ${response.body}');
setState(() {
var convertDataToJson = jsonDecode(response.body);
data = convertDataToJson["event"];
print(data);
});
return "Success";
}```
Can you please suggest a way as to how I can display the data properly in flutter?

Use FutureBuilder to get data from api like this :-
FutureBuilder(
future: yourMethodName(),
builder: (context, AsyncSnapshot<NameOfModelClass> snapshot) {
if (snapshot.data == null) {
return Center(child: CircularProgressIndicator());
}
// after getting data from api
},
);
Your method can be like this :
Future<NameOfModelClass> YourMethodName() async {
final response = await http.get('Your url here');
return NameOfModelClass.fromJson(json.decode(response.body.toString()));
}
The model class can be generate by using jsonToDart
I hope this help :)

Related

Change the id in the URL according to the selected card

Up!
I am a beginner in Flutter and I am making an application in which I have a first "boats" route. I access to the list of my boats contained in "Card" thanks to this route. Then, I have a second route, accessible from a button in each of these "Cards" allowing me to access the details of each boat.
To retrieve my data, I use a fake API to perform my tests (mockapi.io). For the list of boats, the route is "/boats". Then for the details of each boat, it becomes "/boats/:id/details". Here is my problem, how do I handle the fact that the id changes depending on the boat selected?
Here is the method to access the API:
Future<List<ListDetails>?> getListDetails({required id}) async
{
var client = http.Client();
var uri = Uri.parse('https://63e21b26109336b6cbff9ce9.mockapi.io/api/v1/boats_control/$id/details');
var response = await client.get(uri);
if(response.statusCode == 200)
{
var json = response.body;
return listDetailsFromJson(json);
}
}
And here is my boat_details view, where I try to display the API data:
class ControlListDetailViewState extends State<ControlListDetailView> {
#override
Widget build(BuildContext context) {
late final id = ModalRoute.of(context)?.settings.arguments;
List<ListDetails>? listDetails;
var isLoaded = false;
print(listDetails);
getData() async {
listDetails = await RemoteService().getListDetails(id: id);
if (listDetails != null) {
setState(() {
isLoaded = true;
});
}
}
#override
void initState() {
super.initState();
getData();
}
And here is my model :
import 'dart:convert';
List<BoatsControl> boatsControlFromJson(String str) => List<BoatsControl>.from(json.decode(str).map((x) => BoatsControl.fromJson(x)));
String boatsControlToJson(List<BoatsControl> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class BoatsControl {
BoatsControl({
required this.model,
required this.location,
required this.id,
});
String model;
String location;
String id;
factory BoatsControl.fromJson(Map<String, dynamic> json) => BoatsControl(
model: json["model"],
location: json["location"],
id: json["id"],
);
Map<String, dynamic> toJson() => {
"model": model,
"location": location,
"id": id,
};
}
Finally, here is my widget where I use this model:
Widget build(BuildContext context) {
print('ControlViewState - build');
return Scaffold(
drawer: NavDrawableWidget(), // Hamburger menu
bottomNavigationBar: FooterWidget(), // Footer Copyright
appBar: AppBar(
title: Text("${AppSettings.APP_NAME} | ${AppSettings.APP_VERSION}",
style: TextStyle(fontSize: 16)),
),
body: Column(
children: [
Text('\n${AppSettings.strings.controlTitle}',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)
),
Visibility(
visible: isLoaded,
replacement: const Center(
child: CircularProgressIndicator(),
),
child: const Text(''),
),
if(isLoaded)
Expanded(
child: ListView.builder(
itemCount: boatsControl?.length ?? 0,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.all(8.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
side: BorderSide(color: Colors.black12, width: 2),
),
child: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
ListTile(
title: Text('${boatsControl![index].id} | ${boatsControl![index].model}'),
leading: Icon(Icons.anchor),
),
Row(
children: <Widget>[
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(boatsControl![index].location,
style: TextStyle(fontSize: 14)),
],
),
),
Align(
alignment: Alignment.centerRight,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
CustomFloatingActionControlButton(
onPressed: () =>
{
Navigator.pushNamed(
context, '/controlListDefect',
arguments: boatsControl![index].id
)
},
tag: 'listDefectButton',
icon: Icons.equalizer,
),
],
),
),
],
),
],
),
),
),
);
},
),
)
]
),
);
}
Thank you in advance if you take the time to answer me and help me.

Display updated value everytime button is press firebase flutter

i am trying to displaying the new value every time the user click the button but it keeps displaying the old data. I need to hot restart to see the new data after i update it. I do not know what i did wrong because i am still learning. This is my full code. I hope someone can help me because i am stuck here 3 hours +
TextEditingController _reloadEditingController = new TextEditingController();
int balance = 0;
late int s = int.parse(_reloadEditingController.text);
final _formKey = GlobalKey<FormState>();
String? name;
String email = '';
String phoneNumber = '';
String imageUrl = '';
String joinedAt = '';
String location = '';
void reload() async {
FirebaseFirestore.instance
.collection("users")
.doc(widget.userID)
.update({"balance": balance + s});
}
void getUserData() async {
try {
_isLoading = true;
final DocumentSnapshot userDoc = await FirebaseFirestore.instance
.collection('users')
.doc(widget.userID)
.get();
if (userDoc == null) {
return;
} else {
setState(() {
name = userDoc.get('name');
email = userDoc.get('email');
phoneNumber = userDoc.get('phoneNumber');
imageUrl = userDoc.get('userImage');
location = userDoc.get('location');
balance = userDoc.get('balance');
});
final FirebaseAuth _auth = FirebaseAuth.instance;
User? user = _auth.currentUser;
final _uid = user!.uid;
setState(() {
_isSameUser = _uid == widget.userID;
});
}
} catch (error) {
} finally {
_isLoading = false;
}
}
void initState() {
super.initState();
getUserData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.teal[300],
appBar: AppBar(
title: const Text('Wallet'),
flexibleSpace: Container(
color: Colors.teal[300],
),
leading: IconButton(
onPressed: () {
final FirebaseAuth _auth = FirebaseAuth.instance;
final User? user = _auth.currentUser;
final String uid = user!.uid;
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) => ProfileScreen(
userID: uid,
)));
},
icon: Icon(Icons.arrow_back, size: 40, color: Colors.white)),
),
body: ListView(
children: [
Column(
children: [
Container(
width: 300,
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Color(0xFF006e6e)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
name!,
style: TextStyle(color: Colors.white, fontSize: 18),
),
],
),
],
),
),
Container(
padding: EdgeInsets.all(10),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
Text(
"Balance",
),
],
),
Row(
children: [
Text(
'RM',
),
Container(
child: FutureBuilder<DocumentSnapshot>(
future: FirebaseFirestore.instance
.collection('users')
.doc(widget.userID)
.get(),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
return Text(balance.toString());
},
),
),
],
),
Row(
children: [
Text("Reload your E-Wallet",
)
],
),
Row(
children: [
Form(
key: _formKey,
child: Expanded(
child: TextFormField(
controller: _reloadEditingController,
keyboardType: TextInputType.phone,
),
),
)
],
)
],
),
),
),
Container(
width: 320,
child: MaterialButton(
onPressed: () {
reload();
},
child: Padding(
padding: EdgeInsets.symmetric(vertical: 14),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Reload E-Wallet",
)
],
),
),
),
),
],
)
],
));
You need yo call getUserData when you update your data so change your reload to this:
void reload() async {
int s = int.parse(_reloadEditingController.text); // define this hear
await FirebaseFirestore.instance
.collection("users")
.doc(widget.userID)
.update({"balance": balance + s});
setState(() {});
}
Solution of this problem depends on Stream, because you want the live data.
You want to upload data and download it for show in the UI.
If you try to use StreamBuilder instead of FutureBuilder, I think it may be help..
For me I use GetX package, and since a while I faced the same problem, I will put the URL for my question and see if you can take an idea..
Flutter: live stream with getx has a problem, it shows data without updating

Flutter Tried calling: [] error on list builder

I am showing list-builder i need to show just a static data right now I am just check itemCount right now later'll show data but it's showing error .
Here is my code
class _OrderPageState extends State<OrderPage> {
bool showCards = false;
var data;
#override
void initState() {
this.getOrders();
}
getOrders() async{
final storage = new FlutterSecureStorage();
String userId = await storage.read(key: "_userID");
String url =
'http://retailapi.airtechsolutions.pk/api/orders/customer/${userId}/0';
print(url);
http.Response res = await http.get(
url,
);
var data = json.decode(res.body.toString());
print(data);
if(data['description'].toString() == "Success"){
print(data['Orders']);
print(data['Orders'].length); //its printing 6 here
setState(() {
showCards = true;
});}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Order', style: Theme.of(context).textTheme.headline4),
),
body: showCards ? Container(
child: ListView.builder(
itemCount: data['Orders'].length,
shrinkWrap: true,
padding: EdgeInsets.symmetric(horizontal: 18.0, vertical: 20.0),
itemBuilder: (context, index) {
var order = orderList[index];
return SideInAnimation(index, child:GestureDetector(
onTap: () {
// Get.to(OrderDetailPage(order: order));
},
child: Container(
width: double.infinity,
padding: EdgeInsets.all(12.0),
margin: EdgeInsets.only(bottom: 15.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
border: Border.all(color: Theme.of(context).accentColor),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(order.id,
style: Theme.of(context)
.textTheme
.headline3
.copyWith(color: Theme.of(context).primaryColor)),
SizedBox(height: 12.0),
Text(order.dateOrder, style: Theme.of(context).textTheme.subtitle2),
Divider(),
orderCardItem(context,
title: "order.orderstatus", data: order.orderStatus),
SizedBox(height: 12.0),
orderCardItem(context,
title: "order.items",
data: "${order.totalItem} " + tr("order.itemspurchased")),
SizedBox(height: 12.0),
priceItem(context,
title: "order.price", data: "\$ ${order.totalPrice}"),
],
),
),
));
},
),
) : Container(),
);
}
}
In my function its printing the length by in List builder its showing an error that Tried calling: ` But on the print where API load it's showing the length 6.
First you need to initalize a list or array then simply add your data into that variable and then call this variable to your listview builder
var ordersData = [];
then your getData() method should be like this
getOrders() async {
...
if (data['description'].toString() == "Success") {
ordersData.add(data['Orders']); // Add your data to array or list
print(ordersData.length); //its printing 6 here
}
...
}
Here your Listview like this
ListView.builder(
itemCount: ordersData.length, // Here you need to pass this lenght
...
)

Flutter when comes first time on screen sharedpreferences value shows null

hello friends i really need your help ! i am working on project and i am stuck to get sharedPreferences value when page is load....! this is my photogallery project ! i have photlisting in that u can swipe left and right to see images..! now what is the problem is when i call api to get details... i can get data in my initState() i can see response but in that i can see isLike count is printed ** and saved in my isLike veriable which i Did you mean: declarer...! but when i go to set condition part for the color set ! the first time when page is open isLike is showing null...! but when i scroll i can get value....! what i need is when page is open i want value in isLike ! plz help me i will help u in code to understand
Can u show me any suggestions idea on my code
int index;
int isLike; /// here is my veribe
Future<PhotoDetail> pagedetail() async {
sharedPreferences = await SharedPreferences.getInstance();
Map data = {
"AccessToken": sharedPreferences.getString("AccessToken"),
"CustomerId": sharedPreferences.getInt("CustomerId"),
"ImageId": indexx == null ? widget.images[widget.currentindex].photoId : indexx
};
print(data);
final http.Response response = await http.post(
Constants.CUSTOMER_WEBSERVICE_URL + "/photo/detail",
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(data),
);
var jsonResponse = json.decode(response.body);
if (response.statusCode == 200) {
print("Response status : ${response.statusCode}");
print("Response status : ${response.body}");
isLike = jsonResponse["IsLike"]; //here i saving value when api is run
print("iSLiked Value:" +isLike.toString()); // value is printing here
return PhotoDetail.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load data');
}
}
PageController _pageController;
Future<FolderSummery> _futureSummary;
List<Widget> imagefilter;
#override
void initState() {
setState(() {
pagedetail(); //here is my api run when page is load
});
super.initState();
imageid = widget.ImageId[index].photoId;
_pageController = PageController(initialPage: widget.currentindex);
print("like first time page load :" + isLike.toString()); //showing null isLike
}
void pageChange(int index){ //this method is when i scroll page
setState(() {
pagedetail(); // api is call again and again
indexx = widget.images[index].photoId;
print("When page change Like :" + isLike.toString()); //isLiked is printing here
print("Image ID :" + indexx.toString());
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white54,
leading: Padding(
padding: const EdgeInsets.only(left: 1,top: 5,bottom: 5),
child: Container(
height: 8,
width: 35,
child: InkWell(
onTap: (){
Navigator.pop(context);
},
child: IconButton(
icon: Icon(Icons.keyboard_arrow_left,color: Color(0xfff58634,),size: 40,),
),
)
),
),
title: Center(
child: Text("Dhara Weds Bharat")
),
actions: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 20,top: 5,bottom: 5),
child: Container(
height: 8,
width: 35,
child: IconButton(
icon: Icon(Icons.filter_list,color: Color(0xfff58634),size: 40,),
)
),
),
],
),
extendBodyBehindAppBar: true,
body: Stack(
children: <Widget>[
Container(
child:
Center(
child: PhotoViewGallery.builder(
itemCount: widget.images.length,
builder: (BuildContext context , int index) {
return PhotoViewGalleryPageOptions(
imageProvider:
NetworkImage(widget.images[index].photoPreviewImagePath),
maxScale: PhotoViewComputedScale.covered * 1.8,
minScale: PhotoViewComputedScale.contained * 1.0,
);
},
pageController: _pageController,
enableRotation: false,
scrollDirection: Axis.horizontal,
onPageChanged: pageChange,
loadingBuilder: (BuildContext context , ImageChunkEvent event){
return Center(child: CircularProgressIndicator(),);
},
)
)
),
Positioned(
bottom: 10,
left: 30,
right: 30,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
InkWell(
child: InkWell(
child: Icon(Icons.thumb_up,size: 20,color: isLike == 1 ? Color(0xfff58634) :
Colors.white), //HERE IS THE ISSUE WHEN I COME FIRST TIME VALUE IS NULL ! BUT WHEN SCROOLLING VALU IS PRINTING
),
),
InkWell(
child: Icon(Icons.comment,size: 20,color: Colors.white),
),
InkWell(
onTap: (){},
child: Icon(Icons.share,size: 20,color: Colors.white,),
),
InkWell(
onTap: (){},
child: Icon(Icons.photo_album,size: 20,color: Colors.white,),
),
InkWell(
onTap: (){},
child: Icon(Icons.print,size: 20,color: Colors.white,),
),
InkWell(
onTap: (){},
child: Icon(Icons.card_giftcard,size: 20,color: Colors.white,),
),
]
),
),
],
),
);
}
DO U HAVE ANY TIPS PLZ EDIT MY CODE AND GIVE ME PROPER SOLUTION PLZ..
API RESPONSE
import 'dart:convert';
PhotoDetail photoDetailFromJson(String str) => PhotoDetail.fromJson(json.decode(str));
String photoDetailToJson(PhotoDetail data) => json.encode(data.toJson());
class PhotoDetail {
PhotoDetail({
this.successCode,
this.successMessage,
this.likeCount,
this.commentCount,
this.selectedCount,
this.isLike,
});
String successCode;
String successMessage;
int likeCount;
int commentCount;
int selectedCount;
int isLike;
factory PhotoDetail.fromJson(Map<String, dynamic> json) => PhotoDetail(
successCode: json["SuccessCode"],
successMessage: json["SuccessMessage"],
likeCount: json["LikeCount"],
commentCount: json["CommentCount"],
selectedCount: json["SelectedCount"],
isLike: json["IsLike"],
);
Map<String, dynamic> toJson() => {
"SuccessCode": successCode,
"SuccessMessage": successMessage,
"LikeCount": likeCount,
"CommentCount": commentCount,
"SelectedCount": selectedCount,
"IsLike": isLike,
};
}

RangeError (index): Invalid value: Only valid value is 0: 1

I am new to flutter. I am trying to add the list of data to the view. The list of data have different sets of order items with different lengths. I am getting the data from the API but due to the different length of order data, I am getting the error as the image below. I have the json api as follows:
{
"status":"success",
"message":"Data Fetched",
"data":{
"list":[
{
"id":27,
"order_code":"7wfelnkhuodlbvdseley1",
"chef_id":1,
"user_id":1,
"order_status":1,
"status":1,
"order_datetime":"2020-01-21 18:05:00",
"user_location_id":1,
"price":1600,
"coupon_id":null,
"use_coupon":0,
"discount":0,
"final_price":1600,
"vat_amt":208,
"delivery_charge_amt":0,
"payment_id":1,
"delivery_time":null,
"delivery_user_id":null,
"payment_status":0,
"payment_price":null,
"payment_time":null,
"reject_message":null,
"created_at":"2020-01-21 18:05:00",
"updated_at":"2020-01-21 18:07:46",
"orderdata":[
{
"id":30,
"order_code_id":27,
"chef_id":1,
"food_id":17,
"user_id":1,
"additional_info":null,
"food_qty":4,
"instruction":null,
"price":400,
"food":{
"id":17,
"name":"Prawns Chilli",
"description":"<p>Seared prawns smothered in a spicy, sticky Asian sauce,
these Asian Chilli Garlic Prawns will have you smacking your
lips in utter satisfaction, feeling like you’ve just dined at a fancy modern
Thai restaurant.<wbr /> </p>",
"ingredient_detail":null,
"price":500,
"discount_price":400,
"ribbon_text":null,
"image":"1576657695-prawn chilli3.jpg",
"banner_image":null,
"published_date":"2019-12-18",
"is_offer":1
}
}
]
},
{
"id":29,
"order_code":"lzquyrmthdahxmjm81ja1",
"chef_id":1,
"user_id":1,
"order_status":1,
"status":1,
"order_datetime":"2020-01-21 19:17:52",
"user_location_id":1,
"price":280,
"coupon_id":null,
"use_coupon":0,
"discount":0,
"final_price":280,
"vat_amt":36.4,
"delivery_charge_amt":50,
"payment_id":1,
"delivery_time":null,
"delivery_user_id":null,
"payment_status":0,
"payment_price":null,
"payment_time":null,
"reject_message":null,
"created_at":"2020-01-21 19:17:52",
"updated_at":"2020-01-21 19:18:30",
"orderdata":[
{
"id":33,
"order_code_id":29,
"chef_id":1,
"food_id":11,
"user_id":1,
"additional_info":null,
"food_qty":2,
"instruction":null,
"price":250,
"food":{
"id":11,
"name":"Chicken burger",
"description":"<p>The juicyness of the meat will make you feel heaven.</p>",
"ingredient_detail":null,
"price":300,
"discount_price":250,
"ribbon_text":null,
"image":"1576654603-chick burger.jpg",
"banner_image":null,
"published_date":"2019-12-18",
"is_offer":1
}
},
{
"id":34,
"order_code_id":29,
"chef_id":1,
"food_id":4,
"user_id":1,
"additional_info":null,
"food_qty":2,
"instruction":null,
"price":140,
"food":{
"id":4,
"name":"Momo",
"description":"<p>This juicy steamed momos are prepared from the ground water buffalo meat and are called \"Buff momo\". The wrappers are very thinly rolled and the filling is deliciously spicy and juicy, served along with tangy yellow chutney and classic spicy tomato sauce that compliments the taste of steamed momos.</p>",
"ingredient_detail":"<p>Tomato, Ground meat ,Flour, Chilli pepper, Garlic, Ginger, Scallion, Black pepper and Soy sauce</p>",
"price":150,
"discount_price":140,
"ribbon_text":null,
"image":"1576651666-momo.jpg",
"banner_image":null,
"published_date":"2019-11-18",
"is_offer":1
}
}
]
}
]
}
}
My Full Widget Code:
class OnProcessPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _OnProcessTile();
}
}
class _OnProcessTile extends State<OnProcessPage> {
bool _isLoading = false;
List<ListD> foodData = [];
List<Orderdata> orderData = [];
SharedPreferences sharedPreferences;
#override
void initState() {
super.initState();
setState(() {
_isLoading = true;
});
getPrefs();
getOnProcessRequest();
}
#override
Widget build(BuildContext context) {
return Center(
child: Stack(
children: <Widget>[
Opacity(
opacity: _isLoading
? 0.3
: 1, // You can reduce this when loading to give different effect
child: AbsorbPointer(
absorbing: _isLoading,
child: _buildCardList(context),
),
),
Opacity(
opacity: _isLoading ? 1.0 : 0,
child: Center(
child: CircularProgressIndicator(
backgroundColor: Theme.of(context).primaryColor,
),
)),
],
));
}
Widget _buildCardList(BuildContext context) {
return ListView.builder(
itemCount: foodData == null ? 0 : foodData.length,
itemBuilder: (context, int index) {
return Wrap(
children: <Widget>[
Container(
margin: EdgeInsets.only(bottom: 10),
child: Card(
child: Column(
children: <Widget>[
_buildCardView(context, index),
_cardBottomView(context, index)
],
)))
],
);
});
}
Widget _buildCardView(BuildContext context, int index) {
return Wrap(
children: <Widget>[
Container(
child: Container(
margin: EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
_cardTopSection(context, index),
_cardMiddleSection(context, index),
_cardTotalPrice(context, index),
Container(
height: 1,
color: Color.fromRGBO(232, 232, 232, 1),
),
],
),
),
),
],
);
}
Widget _cardTotalPrice(BuildContext context, int i) {
return Container(
margin: EdgeInsets.only(bottom: 5.0),
child: Padding(
padding: EdgeInsets.only(top: 3, bottom: 3),
child: Row(
children: <Widget>[
Expanded(
child: Text(""),
),
Expanded(
child: Text("Total",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
)),
),
Expanded(
child: Text(
"${foodData[i].finalPrice}",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
)
],
),
),
);
}
Widget _cardTopSection(BuildContext context, int index) {
return Container(
color: Color.fromRGBO(232, 232, 232, 1),
child: Row(
children: <Widget>[
_topLeftSection(index),
_topmiddleSection(index),
_toprightSection(index)
],
),
);
}
Widget _cardMiddleSection(BuildContext context, int i) {
return Container(
margin: EdgeInsets.only(top: 10.0),
child: ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount:
foodData[i].orderdata == null ? 0 : foodData[i].orderdata.length,
itemBuilder: (context, i) {
print("Item Builder");
print(i);
print("Item Builder");
return _cardMiddleItems(i);
}),
);
}
Widget _cardMiddleItems(int i) {
print("Middle");
print(i);
print("Middle");
return Container(
margin: EdgeInsets.only(bottom: 5.0),
child: Padding(
padding: EdgeInsets.only(top: 3, bottom: 3),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Text("${orderData[i].food.name}"),
),
Expanded(
child: Text("${orderData[i].foodQty}"),
),
Expanded(
child: Text("${orderData[i].price}"),
),
],
),
),
);
}
Widget _topLeftSection(int index) {
return Container(
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/momo.jpg'),
backgroundColor: Colors.lightGreen,
radius: 24.0,
),
);
}
Widget _topmiddleSection(int i) {
return Expanded(
child: Container(
child: Column(
children: <Widget>[
Text("Coldplay "),
Text("${foodData[i].createdAt}")
// new Text("Hi whatsup?"),
],
),
),
);
}
Widget _toprightSection(int index) {
return Expanded(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text(
"#" + "${foodData[index].id}",
style: TextStyle(color: Colors.black, fontSize: 18.0),
),
],
),
),
);
}
Widget _cardBottomView(BuildContext context, int index) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
"Order Status",
style: TextStyle(fontSize: 18),
),
RaisedButton(
onPressed: () => {},
color: Colors.green,
child: Text(
"Cooking",
style: TextStyle(color: Colors.white),
),
),
RaisedButton(
onPressed: () => {
sharedPreferences.setBool('process', true),
sharedPreferences.setBool('new', false),
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => RequestDetails(),
settings: RouteSettings(
arguments: foodData[index],
),
))
},
color: Theme.of(context).primaryColor,
child: Text("Details", style: TextStyle(color: Colors.white)),
),
],
);
}
Future<NewRequestResponse> getOnProcessRequest() async {
print("OnProcess");
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
String token = sharedPreferences.getString("api_token");
Map<String, String> headers = {"Authorization": token};
var jsonResponse;
NewRequestResponse newRequestResponse;
var response = await http.post(
"url",
headers: headers);
if (response.statusCode == 200) {
print("Onprocess Inside 200");
jsonResponse = json.decode(response.body);
print(jsonResponse);
if (jsonResponse != null) {
newRequestResponse = new NewRequestResponse.fromJson(jsonResponse);
print(newRequestResponse);
setState(() {
foodData = newRequestResponse.data.list;
for (int i = 0; i < foodData.length; i++) {
orderData = foodData[i].orderdata;
}
});
setState(() {
_isLoading = false;
});
return newRequestResponse;
} else {
setState(() {
_isLoading = false;
});
return null;
}
} else {
setState(() {
_isLoading = false;
});
jsonResponse = json.decode(response.body.toString());
newRequestResponse = new NewRequestResponse.fromJson(jsonResponse);
print("onProcessRequest outside 200");
return newRequestResponse;
}
}
void getPrefs() async {
sharedPreferences = await SharedPreferences.getInstance();
}
}
It's a little bit tricky, so I hope I can understand the bug, but to me the problem seems to be on your getOnProcessRequest at this line:
for (int i = 0; i < foodData.length; i++) {
orderData = foodData[i].orderdata;
}
you're updating (and overwriting) orderData at each cycle of foodData. I don't think it is the right thing to do.
As much as I understood what should happen is
for each foodData, get the list of orderData.
But foodData is a list, and orderData too. You should, I think, link these items, so that for each foodData you can access to its own orderData list.
EDIT:
I cannot provide a full solution since would take me too much honestly.
But I came up with an example
final Map<String, dynamic> myApi = {
"list": [
{
"id": 1,
"orderdata": [
{"title": "food1"},
{"title": "food2"}
]
},
{
"id": 2,
"orderdata": [
{"title": "food3"},
{"title": "food4"}
]
},
]
};
class OrderData {
final String title;
OrderData(this.title);
#override
String toString() {
return title;
}
}
class FoodData {
final int id;
final List<OrderData> orderData;
FoodData(this.id, this.orderData);
}
void main() {
final tmpMap = (myApi['list'] as List<Map<String, Object>>);
print(tmpMap);
List<FoodData> myList = tmpMap.map<FoodData>((elem) {
final value = elem;
final _id = value['id'] as int;
final List<OrderData> _orderData =
(value['orderdata'] as List<Map<String, String>>)
.map<OrderData>((order) => OrderData(order['title']))
.toList();
return FoodData(_id, _orderData);
}).toList();
print(myList.length);
for (int i = 0; i < myList.length; i++) {
for (int j = 0; j < myList[i].orderData.length; j++) {
print("i: $i, j: $j, elem: ${myList[i].orderData[j]}");
}
}
}
Now at the end what you need is to change your getOnProcessRequest, using a single list, so delete your orderdata, and use only fooddata, and now your foodData would have for each element (food) also a internal rappresentation of the order.
When you want to instanciate the ListView.builder:
For the first (outer ListView) you would use fooddata.length
for the second (inner ListView) you would use foodata[i].orders.length
Hope this would help you with find your right solution