Flutter images loading issue after reload display but not first time - flutter

Trying to display cover image based on bookList which is RxList from getX but after hot reload it displays that particular book only. Need to load it instantly as soon as the page load.
Tried setstate too but UI is not updating the first time. Please help. Thank you.
Below is the screenshot images not getting displayed first time but after hot restart.
Here images problem:
HorizontalGrid Widget which based on horizontalGridTitle open the specific book
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:matab/constants/constants.dart';
import 'package:matab/controllers/cart_book_controller.dart';
import 'package:matab/models/book.dart';
import 'package:matab/ui/pages/styles.dart';
import '../../../controllers/book_controller.dart';
import '../../general_widgets/book_magazine_tapbar.dart';
import '../../general_widgets/my_network_image.dart';
import '../item_details/book_details_page.dart';
class HorizontalGrid extends StatefulWidget {
final String horizontalGridTitle;
const HorizontalGrid({Key? key, required this.horizontalGridTitle})
: super(key: key);
#override
State<HorizontalGrid> createState() => _HorizontalGridState();
}
class _HorizontalGridState extends State<HorizontalGrid> {
late RxList<dynamic> bookList;
final BookController bookController = Get.find(tag: 'bookController');
final CartBookController cartBookController =
Get.find(tag: 'cartBookController');
#override
void initState() {
bookList = bookController.getSpecifiedBooks(widget.horizontalGridTitle);
super.initState();
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(20.0, 20, 20, 20),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
widget.horizontalGridTitle.tr,
style: TextStyle(
color: secondaryColor,
fontSize: 20,
fontWeight: FontWeight.bold),
),
GestureDetector(
onTap: () {
Get.to(() => BookMagazineTapbar(
titleText: widget.horizontalGridTitle,
));
},
child: Row(
children: [
Text(
"seeAll".tr,
style: TextStyle(
color: mainColor,
fontSize: 20,
fontWeight: FontWeight.bold),
),
Icon(Icons.arrow_forward, color: mainColor)
],
),
)
],
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 30, 20, 10),
child: Column(
children: [
SizedBox(
width: double.infinity,
height: 140,
child: GridView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
),
itemCount: bookList.length,
itemBuilder: (context, index) {
return SizedBox(
child: GestureDetector(
onTap: () {
bookList[index].coverImage;
Get.to(BookDetailsPage(
type: Constants.bookConst,
index: index,
cartButtonText: 'addToCart'.tr,
));
},
child: Obx(
() => CachedNetworkImage(
key: widget.key,
imageUrl: bookList[index].coverImage,
),
)));
},
),
)
],
)),
],
),
);
}
}
This is called based on
getSpecifiedBooks(String title) {
// debugPrint("requested book is $title");
if (title == Constants.recommendedConst) {
debugPrint("recommended requested");
return recommendedBooksList;
} else if (title == Constants.latestByMatabConst) {
return latestBooksList;
} else if (title == Constants.onSaleConst) {
return onSaleList;
} else if (title == Constants.favoritesConst) {
return favoriteBookList;
} else if (title == Constants.allItemsConst) {
return bookList;
} else if (title == Constants.searchConst) {
return bookList;
} else {
return [];
}
}
Afterwards data coming from firebase perfectly in latestBooks:
RxList<dynamic> latestBooks = await databaseService.getLatestBooks();
Future<RxList> getLatestBooks() async {
RxList books = [].obs;
RxInt itemCount = 1.obs;
Query<Map<String, dynamic>> booksQuery = firestoreInstance
.collection('books')
.orderBy('createdAt', descending: true)
.limit(10);
await booksQuery.get().then(
(value) {
for (var doc in value.docs) {
Book bookItem = Book(
author: doc['author'],
title: doc['title'],
price: doc['price'].toDouble(),
coverImage: doc['coverImage'],
bookID: doc.id,
ratings: doc['ratings'].toDouble(),
description: doc['description'],
discountPercentage: doc['discountPercentage'],
isLiked: false,
itemCount: itemCount,
);
books.add(bookItem);
}
},
);
return books;
}
Finally latestBooks is assigned to latestBooksList:
final latestBooksList = [].obs;
latestBooksList.assignAll(latestBooks);

Related

Recommended books list display based on a string constant returns exception

I need to show recommended books based on a string constant 'Recommended', but when I call, the method it returns
EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE
The following ImageCodecException was thrown resolving an image codec:
Failed to load network image.
Image URL:
Where image is getting fine from firebase along with all other fields. Below is the getrecommendedbooks method that
I do display fields onto the Page. PLEASE HELP.
THANK YOU.
Here is the code:
getSpecifiedBooks(String title) {
// debugPrint("requested book is $title");
if (title == Constants.recommendedConst) {
debugPrint("recommended requested");
return recommendedBooksList;
} else if (title == Constants.latestByMatabConst) {
return latestBooksList;
} else if (title == Constants.onSaleConst) {
return onSaleList;
} else if (title == Constants.favoritesConst) {
return favoriteBookList;
} else if (title == Constants.allItemsConst) {
return bookList;
} else if (title == Constants.searchConst) {
return bookList;
} else {
return [];
}
}
class BookController extends GetxController {
final recommendedBooksList = [].obs;
void onInit() {
fetchBooks();
super.onInit();
}
void fetchBooks() async {
try {
isLoading(true);
var books = await databaseService.getBooks();
// var favoriteBookIDs = await databaseService.getFavoriteBookIDs();
RxList<dynamic> recommendedBooks =
await databaseService.getRecommendedBooks();
RxList<dynamic> latestBooks = await databaseService.getLatestBooks();
RxList<dynamic> onSaleBooks = await databaseService.getOnSaleBooks();
bookList.assignAll(books);
// await getFavoriteBooks(favoriteBookIDs);
recommendedBooksList.assignAll(recommendedBooks);
latestBooksList.assignAll(onSaleBooks);
// latestBooksList.assignAll(latestBooks); //TODO uncomment this line and comment one above it when books data is updated in firebase with createdAt field in books
onSaleList.assignAll(books);
debugPrint("fetched books");
} finally {
isLoading(false);
}
}
Future<RxList> getRecommendedBooks() async {
RxList books = [].obs;
RxInt itemCount = 1.obs;
Query<Map<String, dynamic>> booksQuery = FirebaseFirestore.instance
.collection("books")
.where("isRecommended", isEqualTo: true);
await booksQuery.get().then(
(value) {
for (var doc in value.docs) {
Book bookItem = Book(
author: doc['author'],
title: doc['title'],
price: doc['price'].toDouble(),
coverImage: doc['coverImage'],
bookID: doc.id,
rating: doc['ratings'].toDouble(),
description: doc['description'],
discountPercentage: doc['discountPercentage'],
isLiked: false,
itemCount: itemCount,
);
books.add(bookItem);
}
},
);
return books;
}
Display Recommended Widget:
#override
Widget build(BuildContext context) {
return OutlinedButton(
child: const Text(' Show Recommended Books',
style: TextStyle(color: Colors.white)),
onPressed: () {
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => HomePageScreen()),
// );
// Navigator.pop(context);
Get.off(VerticalGrid(verticalGridTitle: Constants.recommendedConst));
},
);
}
}
Image Widget Render:
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.fromLTRB(20.0, 20, 20, 20),
child: Column(children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
widget.verticalGridTitle,
style: TextStyle(
color: secondaryColor,
fontSize: 20,
fontWeight: FontWeight.bold),
),
GestureDetector(
onTap: () {
Get.to(() => BookMagazineTapbar(
titleText: widget.verticalGridTitle,
));
},
child: Row(
children: [
Text(
"seeAll".tr,
style: TextStyle(
color: mainColor,
fontSize: 20,
fontWeight: FontWeight.bold),
),
Icon(Icons.arrow_forward, color: mainColor)
],
),
)
],
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 30, 20, 20),
child: Container(
color: Colors.white,
child: GridView.count(
crossAxisCount: 2,
crossAxisSpacing: 2.0,
mainAxisSpacing: 2.0,
shrinkWrap: true,
scrollDirection: Axis.vertical,
physics: const NeverScrollableScrollPhysics(),
children: List.generate(bookList.length, (index) {
return Padding(
padding: const EdgeInsets.only(bottom: 18.0),
child: GestureDetector(
onTap: () {
if (cartBookController.isInTheCart(index)) {
} else {}
Get.to(BookDetailsPage(
type: Constants.bookConst,
index: index,
cartButtonText: 'Add to Cart',
));
},
child: MyNetworkImage(
imageUrl: bookList[index].coverImage,
),
),
);
}),
)),
)
])),
);
}

Everything matches but I still get "Bad state: field does not exist within the DocumentSnapshotPlatform"

So i'm pretty lost trying to get my app to fetch not only the desired text from firestore but also the image i placed there. I know the error "Bad state: field does not exist within the DocumentSnapshotPlatform" implies that either I'm missing field or there's something wrong with at least one of those fields. There's only four things I'm trying to fetch from firestore "imgUrl, title, desc, organizer" i have checked for spelling and order and i can't figure it out. I have also checked firestore to see if the order and spelling was correct and i dont see what's the issue. Please help, Thank you so much in advanced.
////////////////////////////// News Class Starts\\\\\\\\\\\\\\
import 'package:myfuji/screens/CrudMethods.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'CrudMethods.dart';
import 'add_blog.dart';
class News extends StatefulWidget {
#override
_NewsState createState() => _NewsState();
}
class _NewsState extends State<News> {
CrudMethods crudMethods = CrudMethods();
late QuerySnapshot blogSnapshot;
#override
void initState() {
crudMethods.getData().then((result) {
blogSnapshot = result;
setState(() {});
});
super.initState();
}
Widget blogsList() {
return ListView.builder(
padding: const EdgeInsets.only(top: 24),
itemCount: blogSnapshot.docs.length,
itemBuilder: (context, index) {
return BlogTile(
organizer: blogSnapshot.docs[index].get('Organizer'),
desc: blogSnapshot.docs[index].get('desc'),
imgUrl: blogSnapshot.docs[index].get('imgUrl'),
title: blogSnapshot.docs[index].get('title'),
);
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Events"),
),
body: Container(
child: blogSnapshot != null
? blogsList()
: const Center(
child: CircularProgressIndicator(),
)),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => AddBlog()));
},
),
);
}
}
class BlogTile extends StatelessWidget {
final String imgUrl, title, desc, organizer;
const BlogTile(
{required this.organizer,
required this.desc,
required this.imgUrl,
required this.title});
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(bottom: 24, right: 16, left: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(8)),
child: Image.network(
imgUrl,
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
height: 200,
),
),
),
const SizedBox(height: 16),
Text(
title,
style: const TextStyle(fontSize: 17),
),
const SizedBox(height: 2),
Text(
'$desc - By $organizer',
style: const TextStyle(fontSize: 14),
)
],
),
);
}
}
///////////////////////////////////////////// class AddBlog begins here \\\\\\\\\\\
import 'dart:io';
import 'package:myfuji/screens/CrudMethods.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:random_string/random_string.dart';
class AddBlog extends StatefulWidget {
#override
_AddBlogState createState() => _AddBlogState();
}
class _AddBlogState extends State<AddBlog> {
//
late File selectedImage;
final picker = ImagePicker();
bool isLoading = false;
CrudMethods crudMethods = new CrudMethods();
Future getImage() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
if (pickedFile != null) {
selectedImage = File(pickedFile.path);
} else {
print('No image selected.');
}
});
}
Future<void> uploadBlog() async {
if (selectedImage != null) {
// upload the image
setState(() {
isLoading = true;
});
Reference firebaseStorageRef = FirebaseStorage.instance
.ref()
.child("events/")
.child("${randomAlphaNumeric(9)}.jpg");
final UploadTask task = firebaseStorageRef.putFile(selectedImage);
var imageUrl;
await task.whenComplete(() async {
try {
imageUrl = await firebaseStorageRef.getDownloadURL();
} catch (onError) {
print("Error");
}
print(imageUrl);
});
// print(downloadUrl);
Map<String, dynamic> blogData = {
"imgUrl": imageUrl,
"Organizer": authorTextEditingController.text,
"title": titleTextEditingController.text,
"desc": descTextEditingController.text
};
crudMethods.addData(blogData).then((value) {
setState(() {
isLoading = false;
});
Navigator.pop(context);
});
// upload the blog info
}
}
//
TextEditingController titleTextEditingController =
new TextEditingController();
TextEditingController descTextEditingController = new TextEditingController();
TextEditingController authorTextEditingController =
new TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Create Blog"),
actions: [
GestureDetector(
onTap: () {
uploadBlog();
},
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Icon(Icons.file_upload)),
)
],
),
body: isLoading
? Container(
child: Center(
child: CircularProgressIndicator(),
))
: SingleChildScrollView(
child: Container(
margin: EdgeInsets.symmetric(horizontal: 16),
child: Column(
children: [
GestureDetector(
onTap: () {
getImage();
},
child: selectedImage != null
? Container(
height: 150,
margin: EdgeInsets.symmetric(vertical: 24),
width: MediaQuery.of(context).size.width,
child: ClipRRect(
borderRadius:
BorderRadius.all(Radius.circular(8)),
child: Image.file(
selectedImage,
fit: BoxFit.cover,
),
),
)
: Container(
height: 150,
decoration: BoxDecoration(
color: Colors.grey,
borderRadius:
BorderRadius.all(Radius.circular(8))),
margin: EdgeInsets.symmetric(vertical: 24),
width: MediaQuery.of(context).size.width,
child: Icon(
Icons.camera_alt,
color: Colors.white,
),
),
),
TextField(
controller: titleTextEditingController,
decoration: InputDecoration(hintText: "enter title"),
),
TextField(
controller: descTextEditingController,
decoration: InputDecoration(hintText: "enter desc"),
),
TextField(
controller: authorTextEditingController,
decoration:
InputDecoration(hintText: "enter author name"),
),
],
)),
),
);
}
}
///////////////////////////////////////////// class CrudMethods begins here \\\\\\\\\\\
import 'package:cloud_firestore/cloud_firestore.dart';
class CrudMethods {
Future<void> addData(blogData) async {
print(blogData);
FirebaseFirestore.instance
.collection("events/")
.add(blogData)
.then((value) => print(value))
.catchError((e) {
print(e);
});
}
getData() async {
return await FirebaseFirestore.instance.collection("events/").get();
}
}
/////////////////////////////////////////////firestore\\\\\\\\\\\\\
This maybe related to having “/“ after collection name here:
.collection("events/")
Instead try this:
.collection("events")
Also it may be best to change child to collection here:
Reference firebaseStorageRef = FirebaseStorage.instance
.ref()
.child("events/")
Try to see if you get data back by running this:
itemCount: blogSnapshot.docs.length,
itemBuilder: (context, index) {
QuerySnapshot snap = blogSnapshot.data; // Snapshot
List<DocumentSnapshot> items = snap.documents; // List of Documents
DocumentSnapshot item = items[index]; Specific Document
return BlogTile(
organizer: item.data['Organizer'],
desc: item.data['desc'],
imgUrl: item.data['imgUrl'],
title: item.data['title'],
);
},
I think you need to utilize a QueryDocumentSnapshot to access the data in the document.

FLUTTER : How to only rebuild the top page in stack flutter

I have an issue with rebuilding pages in the stack with Flutter
This is all my users and have added the search to the top appBar.
But it works with conditions to see if it is widgets there then get height of the widgets that is being fixed underneath the appBar...But that happens asynchronously.
So when firstLoad it works but when I call setState it then rebuilds all the pages in the stack and with that it looks like this
This is how it looks after a set state. The problem i saw is that the previous pages have an influence. I couldn't find a good viable solution to this. Will explain my architecture.
I have a page Layout that is a container wrapper for all my pages that has it's appBar styles and just sends through the children. But that is the page Layout wrapper that is being rebuild every time the a set States happen
HOW I GET MY WIDGET SIZE
HOW I IMPLEMENTED IT
It goes in the else with the other pages in the stack.. I tried putting it in the initState but it never goes inside because it is used in the other pages in the stack
I only need an implementation to rebuild the TOP page in the stack.
PAGE LAYOUT
// ignore_for_file: prefer_const_constructors
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart';
import 'package:flutterweb/constants.dart';
import 'package:flutterweb/controllers/channel_controller.dart';
import 'package:flutterweb/controllers/user_controller.dart';
import 'package:flutterweb/main.dart';
import 'package:flutterweb/models/channels_model.dart';
import 'package:flutterweb/utils/functions.dart';
import 'package:flutterweb/views/channels/func.dart';
import 'package:flutterweb/views/home/home.dart';
import 'package:flutterweb/views/menu/permissions/choose_assign_group.dart';
import 'package:flutterweb/widgets/builders/KNetworkFadeImage.dart';
import 'package:flutterweb/widgets/builders/kPopups.dart';
import 'package:flutterweb/widgets/drawerDara.dart';
import 'package:get/get.dart';
class CustomAppBar extends StatefulWidget {
final String title;
final List<Map<String, dynamic>>? topTabs;
final TabController? topTabController;
final List<Widget>? children;
final List<Widget>? childrenFixed;
final Function? leftActionFunction;
final Icon? leftActionIcon;
final Drawer? drawer;
final Function? logOutPressed;
final bool showOptionsMenu;
final Widget? optionMenu;
final Widget? bottomNavigationBar;
final String? backGroundImage;
final ScrollController? scrollController;
CustomAppBar({
required this.title,
this.topTabs,
this.topTabController,
this.leftActionFunction,
this.leftActionIcon,
this.children,
this.childrenFixed,
this.drawer,
this.logOutPressed,
this.showOptionsMenu = false,
this.optionMenu,
this.bottomNavigationBar,
this.backGroundImage,
this.scrollController,
});
#override
_CustomAppBarState createState() => _CustomAppBarState();
}
double app_content_height = 0;
double fixedWidgetSize = 0;
String prevTitle = "";
class _CustomAppBarState extends State<CustomAppBar>
with SingleTickerProviderStateMixin {
final GlobalKey<ScaffoldState> scaffoldkey = GlobalKey<ScaffoldState>();
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
_toggleAnimation() {
scaffoldkey.currentState!.openDrawer();
}
double _getAppBarSize() {
double fixedHeightInclude = fixedWidgetSize;
if (widget.topTabs != null) {
fixedHeightInclude += 100;
} else if (widget.title == "") {
fixedHeightInclude += 0;
} else {
fixedHeightInclude += 60;
}
return fixedHeightInclude;
}
#override
Widget build(BuildContext context) {
// if (widget.title != global_title) return SizedBox();
List<Widget> arr = [];
Widget arrView = SizedBox();
double statusBar = 0;
double _width = MediaQuery.of(context).size.width;
Widget? fixedChild = SizedBox();
if ((widget.childrenFixed?.length ?? 0) > 1) {
fixedChild = WidgetSize(
child: Column(children: widget.childrenFixed!),
onChange: (Size size) {
fixedWidgetSize = 0;
setState(() {
fixedWidgetSize = size.height;
});
kPrint("fixedWidgetSize ${size.height}");
},
);
} else {
fixedWidgetSize = 0;
}
// Widget? fixedChild = (widget.childrenFixed?.length ?? 0) > 1
// ? WidgetSize(
// child: Column(children: widget.childrenFixed!),
// onChange: (Size size) {
// fixedWidgetSize = 0;
// setState(() {
// fixedWidgetSize = size.height;
// });
// kPrint("fixedWidgetSize ${size.height}");
// },
// )
// : SizedBox();
app_content_height =
MediaQuery.of(context).size.height - _getAppBarSize() - statusBar;
if (widget.title != "") {
arr.add(
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 2,
child: widget.showOptionsMenu == true
? IconButton(
icon: const Icon(Icons.menu, color: Colors.white),
onPressed: () => _toggleAnimation(),
)
: IconButton(
icon: widget.leftActionIcon ??
const Icon(Icons.arrow_back, color: Colors.white),
onPressed: () {
if (widget.leftActionFunction != null) {
widget.leftActionFunction!();
} else {
if (Navigator.canPop(context)) {
Get.back();
}
}
},
),
),
Expanded(flex: 2, child: SizedBox()),
Expanded(
flex: 10,
child: Center(
child: Text(
widget.title,
style: const TextStyle(color: Colors.white, fontSize: 24.0),
),
),
),
Expanded(
flex: 4,
child: widget.logOutPressed != null
? IconButton(
icon: const Icon(Icons.power_settings_new_outlined,
color: Colors.white),
onPressed: () {
widget.logOutPressed!();
},
)
: widget.optionMenu ?? Container(),
),
],
),
);
}
if (widget.topTabs != null) {
List<Widget> tempTopBar = [];
List<Widget> tempTopView = [];
for (var i = 0; i < widget.topTabs!.length; i++) {
String key = widget.topTabs![i].keys
.toString()
.replaceAll("(", "")
.replaceAll(")", "");
Widget value = widget.topTabs![i][key];
tempTopBar.add(Tab(text: key));
tempTopView.add(SingleChildScrollView(child: value));
}
arr.add(
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Center(
child: Container(
height: 30,
child: DefaultTabController(
length: widget.topTabs!.length,
child: TabBar(
labelPadding: widget.topTabs!.length == 2
? const EdgeInsets.symmetric(horizontal: 40.0)
: const EdgeInsets.symmetric(horizontal: 16.0),
controller: widget.topTabController,
indicatorSize: TabBarIndicatorSize.tab,
indicator: CircleTabIndicator(color: Colors.white, radius: 4),
isScrollable: true,
labelColor: Colors.white,
tabs: tempTopBar,
),
),
),
),
),
);
// arr.add(child);
arrView = Container(
width: _width,
height: app_content_height,
child: TabBarView(
controller: widget.topTabController,
children: tempTopView,
),
);
}
if (widget.children != null) {
arrView = Container(
width: _width,
height: app_content_height,
child: ListView(
// controller: widget.scrollController ?? ScrollController(),
children: widget.children!,
),
);
}
_getStatus() {
if (statusBar > 0) {
Color color = AppColors.kBlue;
return Container(
height: Get.height * 0.03,
width: Get.width,
color: color,
child: const Center(
child: Text(
"",
style: const TextStyle(color: Colors.black),
),
),
);
} else {
return const SizedBox();
}
}
return SafeArea(
child: Material(
child: Stack(
children: [
Scaffold(
resizeToAvoidBottomInset:
true, //That the keyboard shows correctly
extendBodyBehindAppBar: true,
key: scaffoldkey,
appBar: PreferredSize(
preferredSize: Size.fromHeight(
_getAppBarSize()), // here the desired height
child: Container(
decoration: kAppBarBoxDecorations,
child: Column(
children: [
Column(
children: arr,
),
fixedChild,
],
),
),
),
drawer: Drawer(
child: ListView(
children: <Widget>[
UserAccountsDrawerHeader(
accountName: InkWell(
onTap: () {
Channels element =
ChannelController.to.gSelectedChannel.value;
getChannelRoles(element);
},
child: Text(
"${ChannelController.to.gSelectedChannel.value.rolDesc} >",
),
),
accountEmail: Text(
UserController.to.gUserModel.value.email.toString()),
currentAccountPicture: GestureDetector(
child: const CircleAvatar(
backgroundImage: NetworkImage(
"https://images.pexels.com/photos/220453/pexels-photo-220453.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"),
),
onTap: () => print("Current User")),
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image: NetworkImage(
"${URLS.keyBaseUrl}/assets/images/background/background7.jpg")),
),
),
ListTile(
title: const Text("Home"),
trailing: const Icon(Icons.home),
onTap: () =>
Get.toNamed(Home.router, preventDuplicates: false),
),
ListTile(
title: const Text("Menu Permissions"),
trailing: const Icon(Icons.home),
onTap: () => Get.toNamed(ChooseAssignGroup.router,
preventDuplicates: false),
),
const Divider(
thickness: 1.0,
),
drawerData(),
const Divider(
thickness: 1.0,
),
ListTile(
title: const Text("Close"),
trailing: const Icon(Icons.cancel),
onTap: () => Navigator.of(context).pop(),
),
ListTile(
title: const Text("Log Out"),
trailing: const Icon(Icons.logout),
onTap: () => UserController.to.logOutUser(),
),
],
),
),
body: Container(
decoration: widget.backGroundImage != null
? BoxDecoration(
color: Colors.black.withOpacity(0.9),
image: DecorationImage(
fit: BoxFit.cover,
colorFilter: ColorFilter.mode(
Colors.black.withOpacity(0.2), BlendMode.dstATop),
image: NetworkImage(widget.backGroundImage!),
),
)
: BoxDecoration(color: Colors.grey.shade400),
child: Center(
child: Container(
constraints: BoxConstraints(maxWidth: 800),
padding: EdgeInsets.only(
left: 15.0, right: 15.0, top: _getAppBarSize()),
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: arrView,
),
),
),
),
bottomNavigationBar: widget.bottomNavigationBar,
),
],
),
),
);
}
}
class CircleTabIndicator extends Decoration {
final BoxPainter _painter;
CircleTabIndicator({required Color color, required double radius})
: _painter = _CirclePainter(color, radius);
#override
BoxPainter createBoxPainter([onChanged()?]) => _painter;
}
class _CirclePainter extends BoxPainter {
final Paint _paint;
final double radius;
_CirclePainter(Color color, this.radius)
: _paint = Paint()
..color = color
..isAntiAlias = true;
#override
void paint(Canvas canvas, Offset offset, ImageConfiguration cfg) {
final Offset circleOffset =
offset + Offset(cfg.size!.width / 2, cfg.size!.height - radius);
canvas.drawCircle(circleOffset, radius, _paint);
}
}
class WidgetSize extends StatefulWidget {
final Widget child;
final Function onChange;
const WidgetSize({
required this.onChange,
required this.child,
});
#override
_WidgetSizeState createState() => _WidgetSizeState();
}
class _WidgetSizeState extends State<WidgetSize> {
#override
Widget build(BuildContext context) {
SchedulerBinding.instance.addPostFrameCallback(postFrameCallback);
return Container(
key: widgetKey,
child: widget.child,
);
}
var widgetKey = GlobalKey();
var oldSize;
void postFrameCallback(_) {
var context = widgetKey.currentContext;
if (context == null) return;
var newSize = context.size;
if (oldSize == newSize) return;
oldSize = newSize;
widget.onChange(newSize);
}
}
ALL VERIFIED USERS
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutterweb/controllers/channel_controller.dart';
import 'package:flutterweb/controllers/user_controller.dart';
import 'package:flutterweb/main.dart';
import 'package:flutterweb/models/user_model.dart';
import 'package:flutterweb/thirdParty/googleSignin.dart';
import 'package:flutterweb/utils/functions.dart';
import 'package:flutterweb/views/menu/permissions/menu_assign.dart';
import 'package:flutterweb/widgets/builders/kPopups.dart';
import 'package:flutterweb/widgets/buttons/KIconOnlyButton.dart';
import 'package:flutterweb/widgets/builders/KNetworkFadeImage.dart';
import 'package:flutterweb/widgets/builders/customAppBar.dart';
import 'package:flutterweb/widgets/buttons/KButton.dart';
import 'package:flutterweb/constants.dart';
import 'package:flutterweb/widgets/cards/KStudentInfoCard.dart';
import 'package:flutterweb/widgets/cards/kStudentCard.dart';
import 'package:flutterweb/widgets/input/KInputBar.dart';
import 'package:flutterweb/widgets/input/KTextField.dart';
import 'package:flutterweb/widgets/static/kLabel.dart';
import 'package:flutterweb/widgets/text/kInfo.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
class AllVerifiedUsers extends StatefulWidget {
static const String router = "/allVerifiedUsers";
AllVerifiedUsers({Key? key}) : super(key: key);
#override
_MyPageState createState() => _MyPageState();
}
// The controller for the ListView
late ScrollController _controller;
class _MyPageState extends State<AllVerifiedUsers> {
// The controller for the ListView
late ScrollController _controllerTest;
int _page = 1;
final int _limit = 20;
bool _hasNextPage = true;
bool _isFirstLoadRunning = false;
bool _isLoadMoreRunning = false;
List<UserModel> _posts = [];
String searchVal = "";
void _firstLoad() async {
setState(() {
_isFirstLoadRunning = true;
});
try {
List<UserModel> lUserMode = await ChannelController.to
.fetchUsersChannels(_limit, _page, searchVal);
setState(() {
_posts = lUserMode;
});
} catch (err) {
kPrint('Something went wrong');
}
setState(() {
_isFirstLoadRunning = false;
});
}
void _loadMore() async {
if (_isFirstLoadRunning == false &&
_isLoadMoreRunning == false &&
_controller.position.extentAfter < 300) {
setState(() {
_isLoadMoreRunning = true; // Display a progress indicator at the bottom
});
_page += 1; // Increase _page by 1
try {
List<UserModel> lUserMode = await ChannelController.to
.fetchUsersChannels(_limit, _page, searchVal);
if (lUserMode.isNotEmpty) {
setState(() {
_hasNextPage = true;
_posts.addAll(lUserMode);
});
} else {
// This means there is no more data
// and therefore, we will not send another GET request
setState(() {
_hasNextPage = false;
});
}
} catch (err) {
print('Something went wrong!');
}
setState(() {
_isLoadMoreRunning = false;
});
}
}
#override
void initState() {
super.initState();
_firstLoad();
_controller = ScrollController()..addListener(_loadMore);
_controllerTest = ScrollController()
..addListener(() => {kPrint("CustomView Scroll")});
}
#override
void dispose() {
super.dispose();
_controller.removeListener(_loadMore);
}
#override
Widget build(BuildContext context) {
global_title = "All Verified Users";
return CustomAppBar(
title: "All Verified Users",
scrollController: _controllerTest,
childrenFixed: [
kAddSpace(2),
CustomInputBar(
inverse: true,
title: "Search",
onChanged: (String value) {
if (value == "") {
_firstLoad();
return;
}
setState(() {
searchVal = value;
_posts = [];
});
_loadMore();
},
),
],
children: [
kAddSpace(2),
KLabel(
label: "Choose Verified User",
),
kAddSpace(2),
_isFirstLoadRunning
? const Center(
child: CircularProgressIndicator(),
)
: Column(
children: [
SizedBox(
height: app_content_height,
// width: Get.width,
child: ListView.builder(
shrinkWrap: true,
controller: _controller,
itemCount: _posts.length,
itemBuilder: (_, index) {
UserModel item = _posts[index];
return KStudentCard(
imgUrl: "",
onPressed: () {
ChannelController.to.gSelectedMenuUserModel.value =
item;
Get.toNamed(MenuAssign.router);
},
name: "${item.name} ${item.surname}",
);
},
),
),
// when the _loadMore function is running
if (_isLoadMoreRunning == true)
const Padding(
padding: EdgeInsets.only(top: 10, bottom: 40),
child: Center(
child: CircularProgressIndicator(),
),
),
// When nothing else to load
if (_hasNextPage == false)
Container(
padding: const EdgeInsets.only(top: 30, bottom: 40),
color: Colors.amber,
child: const Center(
child: Text('You have fetched all of the content'),
),
),
],
),
kAddSpace(2),
],
);
}
}
Thank you
As I understand it, the idea is a fixed TextArea and a scrollable List beneath. A solution that works without computing any height would be:
final items = List<String>.generate(1000, (i) => 'Item $i');
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
//
// TEXTBOX
//
Container(
color: Colors.red,
child: Padding(
padding: const EdgeInsets.all(16),
child: TextFormField(
// controller: controller,
))),
const SizedBox(height: 16),
//
// LIST
//
Expanded(
child: ListView.builder(
shrinkWrap: true, // IMPORTANT
itemCount: items.length,
itemBuilder: (context, index) {
return Text(items[index]);
})),
]),
);
}

display sticky header list from api

Greeting to all,
I have made a list view using a sticky header where I am displaying the header list and sublist that I am getting from the API response. i am getting the data but I am stuck for displaying it in tile or card list like wise.
below is the image of how I am getting the data -:
and below is the code for sticky header -:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:sticky_headers/sticky_headers.dart';
import 'package:vcura/Model/Vaccination/Get_Vaccine.dart';
import 'package:vcura/Model/Vaccination/Get_Vaccine_ByID.dart';
import 'package:vcura/Provider/auth_provider.dart';
import 'package:vcura/Screens/home/collapsibleDrawer.dart';
import 'package:vcura/Services/Vaccination/Vaccineservice.dart';
import 'package:vcura/Widgets/custom_loader.dart';
class VaccinationPage extends StatefulWidget {
#override
_VaccinationPageState createState() => _VaccinationPageState();
}
class _VaccinationPageState extends State<VaccinationPage>
with SingleTickerProviderStateMixin {
bool isloading = false;
GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
bool drawerOpen = true;
var newFormat = DateFormat("dd-MM-yy");
GetVaccine _vaccine = GetVaccine();
GetVaccineById vaccineById = GetVaccineById();
VaccineService vaccineService = VaccineService();
var idSet = <String>{};
var header = <dynamic>[];
// var subtitle = [];
List<VaccineModel> subtitle = [];
#override
void initState() {
super.initState();
getdata();
}
Future getdata() async {
setState(() {
isloading = true;
});
String authToken = Provider.of<AuthProvider>(context, listen: false).token;
GetVaccine vaccine = await vaccineService.Getvaccine(authToken);
setState(() {
_vaccine = vaccine;
for (var d in _vaccine.data) {
if (idSet.add(d.vaccineAgeCriteria)) {
header.add(d.vaccineAgeCriteria);
}
}
});
setState(() {
isloading = false;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
drawerScrimColor: Colors.transparent,
extendBody: true,
drawer: ComplexDrawer(),
appBar: AppBar(
leading: InkWell(
child: Icon(
Icons.menu,
color: Colors.indigo,
),
onTap: () {
if (drawerOpen) {
scaffoldKey.currentState.openDrawer();
} else {
return null;
}
},
),
centerTitle: true,
title: Text(
'Vaccination',
style: GoogleFonts.ubuntu(
fontSize: 30,
color: Colors.indigo,
),
),
backgroundColor: Colors.white,
actions: [
InkWell(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Icon(
Icons.search,
color: Colors.indigo,
size: 30,
),
),
onTap: () {},
),
],
elevation: 1,
),
body: isloading
? CustomLoader(size: 50, color: Colors.indigoAccent)
: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: Container(
height: MediaQuery.of(context).size.height,
child: ListView.builder(itemBuilder: (context, index) {
subtitle = _vaccine.data
.where((i) => i.vaccineAgeCriteria == header[index])
.toList();
print(subtitle.map((e) => e.vaccine));
return StickyHeaderBuilder(
builder: (context, stuckAmount) {
stuckAmount = stuckAmount.clamp(0.0, 1.0);
return Container(
height: 100.0 - (50 * (1 - stuckAmount)),
color:
Color.lerp(Colors.blue, Colors.red, stuckAmount),
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'${header[index]}',
style: const TextStyle(color: Colors.white),
),
);
},
content: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: List<int>.generate(1, (index) => index)
.map(
(item) => Container(
height: subtitle.length * 50.0,
width: MediaQuery.of(context).size.width,
child: ListTile(
title: Text(
'${subtitle.map((e) => e.vaccine)}'),
), //_vaccine.data[index].vaccine
),
)
.toList(),
),
),
);
})),
),
);
}
}
below is a sample of data that I am getting -
"data": [
{
"id": "0616c0b6-d798-08d974ba51cb",
"vaccine": "Bacillus Calmette–Guérin (BCG)",
"vaccineAgeCriteria": "Birth",
"dose": 1,
"vaccineDate": "1996-12-31T18:30:00"
},
{
"id": "1e109992-d79b-08d974ba51cb",
"vaccine": "Diptheria, Tetanus and Pertussis vaccine (DTwP 1)",
"vaccineAgeCriteria": "6 weeks",
"dose": 1,
"vaccineDate": "0001-01-01T00:00:00"
},
{
"id": "a985b9d5-d7a3-08d974ba51cb",
"vaccine": "Haemophilus influenzae type B (Hib 2)",
"vaccineAgeCriteria": "10 weeks",
"dose": 1,
"vaccineDate": "0001-01-01T00:00:00"
},
{
"id": "1597403a-d7a4-08d974ba51cb",
"vaccine": "Rotavirus 2",
"vaccineAgeCriteria": "10 weeks",
"dose": 1,
"vaccineDate": "0001-01-01T00:00:00"
},
],
"exceptionInfo": null,
"message": null,
"messages": null,
"isSuccess": true
}
please help.
Wrap your ListTile with the ListView.builder.
ListView.builder(
shrinkWrap: true,
physics: ScrollPhysics(),
itemCount: subtitle.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(subtitle[index].vaccine),
);
},
),

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