Why does it keep loading forever? - flutter

there is a problem. I have SOMETIMES no download icon disappears. Or to put it another way, instead of "No more entries", I see a loading circle.
This happens depending on how much data I received. For example, for 5 records there will be an endless download, and for 6 records it will display "There are no more records"
Tell me, what's the problem?
class _MyHomePageState extends State<MyHomePage> {
var ressultat = json.decode(MyApp.resultat)['Transactions'];
final controller = ScrollController();
bool hasMore = true;
int page = 2;
bool isLoading = false;
#override
void initState() {
super.initState();
// fetch();
controller.addListener(() {
if(controller.position.maxScrollExtent == controller.offset) {
fetch();
}
});
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
Future fetch() async {
if(isLoading) return;
isLoading = true;
var token = LoginClass.resJson;
const limit = 9;
try {
final response = await http.post(
Uri.parse(Config.urlReport),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
"Authorization": "Bearer $token"
},
body: json.encode({
"Filters": {
"DateFrom" : MyApp.dateFrom,
"DateTo" : MyApp.dateEnd,
"AmountFrom": MyApp.sumFrom,
"AmountTo": MyApp.sumTo,
"SenderPaymentSystemId": MyApp.dropdownvalue,
"SenderRequisite": MyApp.phoneNum},
"Sorting": {
"Field": MyApp.isCheckedFieldPicker,
"Order": MyApp.isCheckedOrderPicker},
"Pagination": {
"PageNumber": page,
"PageSize": limit
}
})
);
if (response.statusCode == 200) {
var reportResult = (response.body);
print(reportResult);
final List ress = json.decode(reportResult)['Transactions'];
setState(() {
page++;
isLoading = false;
if(MyApp.rowNumber!.length < limit) {
hasMore = false;
}
MyApp.rowNumber?.addAll(ress.map<String>((item) {
final rowNumber = item['RowNumber'].toString();
return rowNumber;
}));
MyApp.walletName?.addAll(ress.map<String>((item) {
final walletName = item['WalletName'].toString();
return walletName;
}));
MyApp.payerPhoneNumber?.addAll(ress.map<String>((item) {
final phoneNumber = item['SenderRequisite'].toString();
return phoneNumber;
}));
MyApp.createdDate?.addAll(ress.map<String>((item) {
final createdDate = item['CreatedDate'].toString();
return createdDate;
}));
MyApp.amount?.addAll(ress.map<String>((item) {
final amount = item['Amount'].toString();
return amount;
}));
});
print(MyApp.createdDate.runtimeType);
} else {
var res = response.statusCode;
print(res);
}
} catch (error) {
print(error);
}
}
Here is all the necessary code, if you need something else, please let me know
child: ListView.builder(
controller: controller,
padding: EdgeInsets.all(5),
itemCount: MyApp.rowNumber!.length + 1,
itemBuilder: (context, index) {
if (index < MyApp.rowNumber!.length) {
return Container(
padding: EdgeInsets.all(5),
margin: EdgeInsets.all(2),
decoration: BoxDecoration(
border: Border.all(color: Colors.black)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
children: [
Container(
margin: EdgeInsets.all(5),
child: Text(' ${MyApp.rowNumber?[index]}', style: TextStyle(fontSize: 15),),
)
],
),
Column(
children: [
Container(
margin: EdgeInsets.all(5),
width: 80,
child: Text('${MyApp.createdDate?[index].replaceFirst(RegExp('T'), '')}', style: TextStyle(fontSize: 15),),
)
],
),
Column(
children: [
Container(
margin: EdgeInsets.all(5),
child: Column(
children: [
Text('${MyApp.walletName?[index]}', style: TextStyle(fontSize: 15),),
Text('${MyApp.payerPhoneNumber?[index]}', style: TextStyle(fontSize: 15),),
],
),
)
],
),
Column(
children: [
Container(
margin: EdgeInsets.all(5),
child: Text('${MyApp.amount?[index]}', style: TextStyle(fontSize: 15),),
)
],
)
],
),
),
],
)
);
} else {
return Padding(
padding: EdgeInsets.symmetric(vertical: 10),
child: Center(
child: hasMore
? const CircularProgressIndicator()
: const Text('Список полностью загружен')
,),
);
}
}
)
UPD: I clarify the question: My first request was sent with a limit of 9 entries, however, if there are less than 9 entries, then there will be an endless download. How to fix it?

you are not setting isLoading as false for HTTP request's response other than 200 and for error.
Future fetch() async {
if(isLoading) return;
isLoading = true;
var token = LoginClass.resJson;
const limit = 9;
try {
final response = await http.post(
Uri.parse(Config.urlReport),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
"Authorization": "Bearer $token"
},
body: json.encode({
"Filters": {
"DateFrom" : MyApp.dateFrom,
"DateTo" : MyApp.dateEnd,
"AmountFrom": MyApp.sumFrom,
"AmountTo": MyApp.sumTo,
"SenderPaymentSystemId": MyApp.dropdownvalue,
"SenderRequisite": MyApp.phoneNum},
"Sorting": {
"Field": MyApp.isCheckedFieldPicker,
"Order": MyApp.isCheckedOrderPicker},
"Pagination": {
"PageNumber": page,
"PageSize": limit
}
})
);
if (response.statusCode == 200) {
var reportResult = (response.body);
print(reportResult);
final List ress = json.decode(reportResult)['Transactions'];
setState(() {
page++;
isLoading = false;
if(MyApp.rowNumber!.length < limit) {
hasMore = false;
}
MyApp.rowNumber?.addAll(ress.map<String>((item) {
final rowNumber = item['RowNumber'].toString();
return rowNumber;
}));
MyApp.walletName?.addAll(ress.map<String>((item) {
final walletName = item['WalletName'].toString();
return walletName;
}));
MyApp.payerPhoneNumber?.addAll(ress.map<String>((item) {
final phoneNumber = item['SenderRequisite'].toString();
return phoneNumber;
}));
MyApp.createdDate?.addAll(ress.map<String>((item) {
final createdDate = item['CreatedDate'].toString();
return createdDate;
}));
MyApp.amount?.addAll(ress.map<String>((item) {
final amount = item['Amount'].toString();
return amount;
}));
});
print(MyApp.createdDate.runtimeType);
} else {
var res = response.statusCode;
isLoading = false;
setState(() {});
print(res);
}
} catch (error) {
isLoading = false;
setState(() {});
print(error);
}
}

Related

Image Slider show images but as it refresh it removes all images and shows that null check operator is used on null value in flutter

I am using slider to show images but when the slider load it shows image at start but when its load all the images it shows null check operator is used on a null value how can i solve this issue if anyone knows about it please let me know about it.
In debug mode it show images loaded but then it set his state on 2nd and 3rd index of images
old data removed and it shows null check operator is used on null value
**Slider Calling **
Stack(
children: [
// AnimationSlider(
// con: _con,
// ),
ItemDetailsImageSlider(
con: _con,
onTap: (int index) {
setState(() {
_con!.secondaryController =
PageController(initialPage: index);
_con!.showImage = true;
});
},
),
_appBar(),
)]);
**Slider**
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:iExchange_it/src/controller/item_controller.dart';
class ItemDetailsImageSlider extends StatelessWidget {
final ItemController? con;
final Function(int index)? onTap;
ItemDetailsImageSlider({this.con, this.onTap});
#override
Widget build(BuildContext context) {
var theme = Theme.of(context);
return Stack(
children: [
Container(
height: MediaQuery.of(context).size.width,
child: PageView.builder(
controller: con!.controller,
physics: PageScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: con!.product!.images!.length,
itemBuilder: (context, index) {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: CachedNetworkImage(
imageUrl: con!.product!.images![index].path,
fit: BoxFit.cover,
),
);
),
Positioned(
bottom: 0,
right: 1,
left: 1,
child: IgnorePointer(
child: Container(
height: 50,
alignment: Alignment.center,
margin: EdgeInsets.only(bottom: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(
(con!.product!.images != null &&
con!.product!.images!.length > 0)
? con!.product!.images!.length
: 1, (index) {
return AnimatedContainer(
duration: Duration(milliseconds: 100),
width: con!.index == index ? 9 : 7,
height: con!.index == index ? 9 : 7,
margin: EdgeInsets.symmetric(horizontal: 5),
decoration: BoxDecoration(
color: con!.index == index
? theme.colorScheme.secondary
: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: theme.focusColor,
blurRadius: 2,
offset: Offset(1, 1))
]),
);
}),
)),
),
),
Align(
alignment: Alignment.topCenter,
child: IgnorePointer(
child: Container(
width: MediaQuery.of(context).size.width,
height: 70,
decoration: BoxDecoration(
gradient: LinearGradient(colors: [
theme.scaffoldBackgroundColor.withOpacity(0.8),
theme.scaffoldBackgroundColor.withOpacity(0),
], stops: [
0.4,
1,
], begin: Alignment.topCenter, end: Alignment.bottomCenter)),
),
),
),
Positioned(
bottom: 0,
child: IgnorePointer(
child: Container(
width: MediaQuery.of(context).size.width,
height: 50,
decoration: BoxDecoration(
gradient: LinearGradient(colors: [
theme.scaffoldBackgroundColor.withOpacity(0),
theme.scaffoldBackgroundColor.withOpacity(1),
], stops: [
0.3,
1
], begin: Alignment.topCenter, end: Alignment.bottomCenter)),
),
),
),
],
);
}
}
**Item Controller**
// ignore_for_file: deprecated_member_use
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:iExchange_it/src/models/item.dart';
import 'package:iExchange_it/src/models/product.dart';
import 'package:iExchange_it/src/models/review.dart';
import 'package:iExchange_it/src/models/user.dart';
import 'package:iExchange_it/src/repository/settings_repository.dart';
import 'package:mvc_pattern/mvc_pattern.dart';
import 'package:iExchange_it/src/repository/product_repository.dart' as repo;
import 'package:iExchange_it/src/repository/review_repository.dart' as reviewRepo;
import '../models/child_category.dart';
class ItemController extends ControllerMVC {
User? currentUser;
Item? item;
PageController? controller;
PageController? secondaryController;
double? index = 0;
Product? product;
bool isMine = false;
bool showImage = false;
bool showDeleteDialog = false;
bool isLoading = false;
List<Product> favorites = <Product>[];
bool isLoadingProducts = false;
List<Review> reviews = <Review>[];
int reviewsCount = 0; //Total Enabled Reviews
ChildCategory? selectedChildCat;
List<Product> catProducts = <Product>[];
GlobalKey<ScaffoldState>? scaffoldKey;
ItemController() {
this.scaffoldKey = new GlobalKey<ScaffoldState>();
controller = PageController();
secondaryController = PageController();
controller!.addListener(() {
setState((){
index = controller!.page;
});
});
}
getFavoriteProducts() async {
setState((){isLoadingProducts = true; this.favorites.clear();});
Stream<Product> stream = await repo.getFavoriteProducts();
stream.listen((_prod) {
_prod.isFavorite = true;
setState((){
this.favorites.add(_prod);
});
},
onError: (e){
print(e);
setState((){isLoadingProducts = false; });
scaffoldKey!.currentState!.showSnackBar(SnackBar(content: Text("Varify your internet connection")));
},
onDone: (){
setState((){isLoadingProducts = false; });
});
}
getProductDetails() async {
Stream<Product> stream = await repo.getProductDetails(product!.id.toString());
stream.listen((_product) {
setState((){
this.product = _product;
});
},
onError: (e){
print(e);
scaffoldKey!.currentState!.showSnackBar(SnackBar(content: Text("Verify your internet connection")));
},
onDone: (){
if(this.product!.latitude != null && this.product!.longitude != null) {
var lat = double.parse(this.product!.latitude.toString());
var long = double.parse(this.product!.longitude.toString());
updateCurrentMarker(LatLng(lat, long));
}
});
}
getProductsByChildCategory(var id) async {
setState((){
isLoadingProducts = true;
this.catProducts.clear();
});
Stream<Product> stream = await repo.getProductsByChildCategory(id);
stream.listen((_product) {
if(this.product!.id.toString() != _product.id.toString()) {
setState(() {
this.catProducts.add(_product);
});
}
},
onError: (e){
print(e);
setState((){isLoadingProducts = false;});
},
onDone: (){
setState((){isLoadingProducts = false;});});
}
getProductReviews() async {
Stream<Review> stream = await reviewRepo.getReviewsOfProduct(product!.id.toString());
stream.listen((_review) {
setState((){
this.reviews.add(_review);
if(_review.status == true || _review.status == 1 || _review.status == "1") {
reviewsCount++;
}
});
},
onError: (e){
print(e);
},
onDone: (){
});
}
deleteProduct() async {
repo.deleteProduct(this.product!.id.toString()).then((value) {
showToast(value ? "Deleted Successfully" : "Unable to delete");
if(value) {
Navigator.of(this.scaffoldKey!.currentContext!).pop(true);
}
}, onError: (e){
print(e);
scaffoldKey!.currentState!.showSnackBar(SnackBar(content: Text("Verify your internet connection")));
});
}
getOpponentUser(var id) async {
// userRepo.getUserProfile(id).then((_user) {
// setState(() {
// Owner = _user;
// });
// });
}
changeReviewStatus(Review _review) async {
setState((){this.isLoading = true;});
reviewRepo.changeReviewStatus(_review).then((value) {
setState((){this.isLoading = false;});
if (value != null) {
for(int i = 0; i<this.reviews.length; i++) {
if(this.reviews[i].id.toString() == value.id.toString()) {
setState((){
this.reviews[i] = value;
if(value.status == true || value.status == 1 || value.status == "1") {
reviewsCount++;
} else {
reviewsCount--;
}
});
}
}
} else {
scaffoldKey!.currentState!.showSnackBar(SnackBar(content: Text("Some Error Occurred, Try later please")));
}
}, onError: (e) {
setState((){this.isLoading = false;});
print(e);
scaffoldKey!.currentState!.showSnackBar(SnackBar(content: Text("Verify your internet connection")));
});
}
toggleFavorite() async {
if(this.product!.isFavorite) {
//Remove Favorite
repo.removeFavorite(this.product!.id).then((value){
if(value) {
showToast("Item removed from favorites");
setState((){
this.product!.isFavorite = false;
});
}
});
} else {
//Add Favorite
repo.addToFavorite(this.product!.id).then((value){
if(value) {
showToast("Item added to favorites");
setState((){
this.product!.isFavorite = true;
});
}
});
}
}
toggleFavoriteById(Product _prod) async {
if(_prod.isFavorite) {
//Delete Favorite
repo.removeFavorite(_prod.id).then((value){
if(value) {
showToast("Item removed from favorites");
favorites.forEach((element) {
if(element.id.toString() == _prod.id.toString()) {
setState((){
element.isFavorite = false;
});
}
});
}
});
}
else {
//Add Favorite
repo.addToFavorite(_prod.id).then((value){
if(value) {
showToast("Item added to favorites");
favorites.forEach((element) {
if(element.id.toString() == _prod.id.toString()) {
setState((){
element.isFavorite = true;
});
}
});
}
});
}
}
downloadImage(String url) async {
// //comment out the next two lines to prevent the device from getting
// // the image from the web in order to prove that the picture is
// // coming from the device instead of the web.
// var url = "https://www.tottus.cl/static/img/productos/20104355_2.jpg"; // <-- 1
// var response = await get(url); // <--2
// var documentDirectory = await getApplicationDocumentsDirectory();
// var firstPath = documentDirectory.path + "/images";
// var filePathAndName = documentDirectory.path + '/images/pic.jpg';
// //comment out the next three lines to prevent the image from being saved
// //to the device to show that it's coming from the internet
// await Directory(firstPath).create(recursive: true); // <-- 1
// File file2 = new File(filePathAndName); // <-- 2
// file2.writeAsBytesSync(response.bodyBytes); // <-- 3
// setState(() {
// imageData = filePathAndName;
// dataLoaded = true;
// });
}
late GoogleMapController mapController;
BitmapDescriptor? customIcon;
bool isMapCreated = false;
String? mapStyle;
List<Marker> allMarkers = [];
initiateLocationController() async {
rootBundle.loadString('assets/map/darkmap.txt').then((string) {
mapStyle = string;
});
}
void setMapStyle(String mapStyle) {
mapController.setMapStyle(mapStyle);
}
updateCurrentMarker(LatLng location) {
// Marker m = Marker(markerId: MarkerId('1'),
// position: location,
// infoWindow: InfoWindow(
// title: "Here it is",
// snippet: "Seller is Here"
// ),
// icon: BitmapDescriptor.defaultMarkerWithHue(
// BitmapDescriptor.hueRed,
// )
// );
setState(() {
mapController.animateCamera(CameraUpdate.newLatLng(location));
allMarkers.clear();
// allMarkers.add(m);
});
}
}

How to make search FLUTTER JSON

I'm a new Flutter user, here I'm having a problem, I'm confused about how to make a search that reads from JSON, here I've created a search menu but I don't understand how to connect to the database. Can you help me to modify my source code so I can do a search. Hopefully good friends can help me make a search function. Thank you friend
datanasabah.dart
GlobalKey<ScaffoldState> _scaffoldState = GlobalKey<ScaffoldState>();
class DataNasabah extends StatefulWidget {
DataNasabah({Key key}) : super(key: key);
final String title = "Data Nasabah";
#override
_DataNasabahState createState() => _DataNasabahState();
}
class _DataNasabahState extends State<DataNasabah> {
ApiService apiService;
ListNasabah _listNasabah;
bool _isLoading = true;
List<Nasabah> data;
final _textHeadStyle =
TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold);
void fetchData() async {
final res = await apiService.getNasabah();
data = res;
setState(() {
_isLoading = false;
});
}
#override
void initState() {
super.initState();
apiService = ApiService();
_listNasabah = new ListNasabah(apiService: apiService);
fetchData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldState,
appBar: AppBar(
title: Text(
'Data Nasabah',
style: TextStyle(color: Colors.white),
),
actions: <Widget>[
MaterialButton(
elevation: 5,
child: Text("CARI", style: _textHeadStyle),
onPressed: () async {
var value = await showTopModalSheet<String>(
context: context, child: DumyModal());
},
),
],
),
body: _listNasabah.createViewList(),
);
}
}
class DumyModal extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
height: MediaQuery.of(context).size.height * .2,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
TextField(
decoration: InputDecoration(
labelText: "NIK Nasabah", //babel text
hintText: "Masukkan NIK Nasabah", //hint text
prefixIcon: Icon(Icons.people), //prefix iocn
hintStyle: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, ), //hint text style
labelStyle: TextStyle(fontSize: 17, color: Colors.black), //label style
)
),
MaterialButton(
color: Colors.orange,
child: const Text("Cari", style: TextStyle(color: Colors.white),),
onPressed: () {
FocusScope.of(context).requestFocus(FocusNode());
},
)
],
),
);
}
}
nasabah_service.dart
class ApiService {
final String baseUrl = '192.168.100.207:8080';
Client client = Client();
Future<List<Nasabah>> getNasabah() async {
final response = await client.get('http://$baseUrl/api/mstdebitur');
print(response.body);
if (response.statusCode == 200) {
final nasabah = (json.decode(response.body) as List)
.map((e) => Nasabah.fromMap(e))
.toList();
return nasabah;
} else {
throw Exception('Failed to load post');
}
}
Future<bool> createNasabah(Nasabah data) async {
String url = new Uri.http("$baseUrl", "/api/mstdebitur/").toString();
final response = await client.post(url,
headers: {"Content-Type": "application/json"},
body: nasabahToJson(data));
if (response.statusCode == 201) {
return true;
} else {
return false;
}
}
Future<bool> updateNasabah(Nasabah data) async {
String url =
new Uri.http("$baseUrl", "/api/mstdebitur/${data.id}").toString();
final response = await client.put(url,
headers: {"Content-Type": "application/json"},
body: nasabahToJson(data));
if (response.statusCode == 200) {
return true;
} else {
return false;
}
}
Future<bool> deleteNasabah(int id) async {
String url = new Uri.http("$baseUrl", "/api/mstdebitur/$id").toString();
final response = await client.delete(url);
if (response.statusCode == 200) {
return true;
} else {
return false;
}
}
}

Flutter weird bug with widget function, sometimes in runs 2 times instead of one

This function have futureBuilder inside and returns another function that returns ListView.
Also I do not want the user to download information from the Internet every time they visit the page, so I put the information downloaded from the Internet into a static variable in class, so i make if else. If this static variable length != 0 , it return me listView instead of make server request with futureBuilder
function that works 2 times instead of one is ListView body
And also this bug created after i added purchases to my application, maybe something wrong there. I don't have any ideas why this happend
this is my complete code
class AddCheckList extends StatefulWidget {
const AddCheckList({Key? key}) : super(key: key);
#override
_AddCheckListState createState() => _AddCheckListState();
}
class _AddCheckListState extends State<AddCheckList> {
String xQueryReqestForCheckListNames = "element CheckListList {for \$a in PACK/OBJECT where (\$a/#inUse = 'True') order by \$a/#name return element CheckList {attribute name {\$a/#name}, attribute sPaid {\$a/#isPaid},attribute oid {\$a/#oid} }}";
String serverLink = "http...";
int addCheckListMethod = 0;
// if addCheckListMethod == 0, then data will download from server and checkLists will be added from server xml data
// if addCheckListMethod == 1, then data will download from assets, and checkLists will be added from assets xml data with getXmlData function
final InAppPurchase _inAppPurchase = InAppPurchase.instance;
final String _productID = '1d7ea644f690ffa';
bool _available = true;
List<ProductDetails> _products = [];
List<PurchaseDetails> _purchases = [];
StreamSubscription<List<PurchaseDetails>>? _subscription;
#override
void initState() {
final Stream<List<PurchaseDetails>> purchaseUpdated = _inAppPurchase.purchaseStream;
_subscription = purchaseUpdated.listen((purchaseDetailsList) {
setState(() {
_purchases.addAll(purchaseDetailsList);
_listenToPurchaseUpdated(purchaseDetailsList);
});
}, onDone: () {
_subscription!.cancel();
}, onError: (error) {
_subscription!.cancel();
});
_initialize();
super.initState();
}
#override
void dispose() {
_subscription!.cancel();
super.dispose();
}
void _initialize() async {
_available = await _inAppPurchase.isAvailable();
List<ProductDetails> products = await _getProducts(
productIds: Set<String>.from(
[_productID],
),
);
setState(() {
_products = products;
});
}
void _listenToPurchaseUpdated(List<PurchaseDetails> purchaseDetailsList) {
purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async {
switch (purchaseDetails.status) {
case PurchaseStatus.pending:
// _showPendingUI();
break;
case PurchaseStatus.purchased:
case PurchaseStatus.restored:
// bool valid = await _verifyPurchase(purchaseDetails);
// if (!valid) {
// _handleInvalidPurchase(purchaseDetails);
// }
break;
case PurchaseStatus.error:
print(purchaseDetails.error!);
// _handleError(purchaseDetails.error!);
break;
default:
break;
}
if (purchaseDetails.pendingCompletePurchase) {
await _inAppPurchase.completePurchase(purchaseDetails);
}
});
}
Future<List<ProductDetails>> _getProducts({required Set<String> productIds}) async {
ProductDetailsResponse response = await _inAppPurchase.queryProductDetails(productIds);
return response.productDetails;
}
void _subscribe({required ProductDetails product}) {
final PurchaseParam purchaseParam = PurchaseParam(productDetails: product);
_inAppPurchase.buyNonConsumable(
purchaseParam: purchaseParam,
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(padding: EdgeInsets.all(14.0), child: listViweBody(addCheckListMethod, serverLink, xQueryReqestForCheckListNames, _products,_subscribe)),
);
}
}
Widget listView(addCheckListMethod, serverLink, product,_subscribe) {
return ListView.separated(
itemCount: CheckListModel.checkListModelNamesFromServer.length,
itemBuilder: (BuildContext context, int index) {
if (CheckListModel.checkListModelNamesFromServer[index].ispaid == false) {
return InkWell(
onTap: () async {
CheckListModel checkList = CheckListModel('', 0, '', 0, 0, 0, '', [], '');
if (addCheckListMethod == 0) {
String xQueryReqestForCheckList = 'for \$a in PACK/OBJECT where \$a/#name="${CheckListModel.checkListModelNamesFromServer[index].name}" return \$a';
var data = await CheckListModel.getDataFromServer(xQueryReqestForCheckList, serverLink);
CheckListModel.addCheckListFromServer(checkList, data);
} else {
CheckListModel.addCheckList(index, checkList);
}
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Добавить описание"),
content: Container(
decoration: BoxDecoration(border: Border.all(color: Color.fromARGB(Desing.colorFromARGBBtn[0], Desing.colorFromARGBBtn[1], Desing.colorFromARGBBtn[2], Desing.colorFromARGBBtn[3]), width: 1), borderRadius: BorderRadius.circular(10)),
child: TextField(
decoration: new InputDecoration.collapsed(hintText: "Описание", border: InputBorder.none),
maxLines: null,
onChanged: (String value) async {
checkList.description = value;
},
),
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text("Отменить"),
),
TextButton(
onPressed: () async {
await checkList.writeToFile(checkList.toJson());
CheckListModel.checkLists.add(checkList);
Navigator.pushNamed(context, '/beforeMainCheckList', arguments: {'index': CheckListModel.checkLists.length - 1});
},
child: Text('Добавить'))
],
);
});
},
child: Container(
decoration: BoxDecoration(border: Border.all(color: Color.fromARGB(Desing.colorFromARGBBtn[0], Desing.colorFromARGBBtn[1], Desing.colorFromARGBBtn[2], Desing.colorFromARGBBtn[3]), width: 1), borderRadius: BorderRadius.circular(10)),
width: 50,
height: 80,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"${CheckListModel.checkListModelNamesFromServer[index].name}",
style: TextStyle(fontSize: 30),
)
],
),
),
);
} else {
if (product.length != 0) {
return showPurchaseCheckLists(product, index,_subscribe);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}
},
separatorBuilder: (BuildContext context, int index) {
return Container(
height: 14,
);
});
}
Widget showPurchaseCheckLists(product, index,_subscribe) {
int getCurrentProduct() {
String? checkListModelid = CheckListModel.checkListModelNamesFromServer[index].checkListId?.toLowerCase();
int indexx = 0;
for (int i = 0; i < product.length; i++) {
if (checkListModelid == product[i].id) {
indexx = i;
}
}
return indexx;
}
return InkWell(
child: Container(
decoration: BoxDecoration(border: Border.all(color: Color.fromARGB(Desing.colorFromARGBBtn[0], Desing.colorFromARGBBtn[1], Desing.colorFromARGBBtn[2], Desing.colorFromARGBBtn[3]), width: 1), borderRadius: BorderRadius.circular(10), color: Color.fromARGB(255, 240, 240, 240)),
width: 50,
height: 80,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"${CheckListModel.checkListModelNamesFromServer[index].name}",
style: TextStyle(fontSize: 25),
),
Text("Купить за ${product[getCurrentProduct()].price}")
],
),
),
onTap: () {
_subscribe(product: product[getCurrentProduct()]);
},
);
}
Widget listViweBody(addCheckListMethod, serverLink, xQueryReqestForCheckListNames, product,_subscribe) {
if (CheckListModel.checkListModelNamesFromServer.length == 0) {
return FutureBuilder(
future: CheckListModel.getDataFromServer(xQueryReqestForCheckListNames, serverLink),
builder: (context, data) {
if (data.connectionState == ConnectionState.done) {
return listView(addCheckListMethod, serverLink, product,_subscribe);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
});
} else {
return listView(addCheckListMethod, serverLink, product,_subscribe);
}
}

How can we access the list item in flutter widget?

I am trying to access the fullName from the list created in my Future function, but unable to do. I tried it through indexing and this method I have tried snapshot.data.fullName, but still unable to retrieve the data, even after returning from future function I was facing problems.
Below is code for User model
class User {
final String fullname;
final String contactno;
final String address;
final String city;
final String gender;
final String email;
User(this.fullname, this.contactno, this.address, this.city, this.gender, this.email);
factory User.fromMap(Map<String, dynamic> json) {
return User(
json['fullname'],
json['contactno'],
json['address'],
json['city'],
json['gender'],
json['email']
);
}
}
Stateful Class Code
class EditProfile extends StatefulWidget {
// final String user_fullname;
// //const EditProfile(this.user_fullname);
// const EditProfile ({ Key key, this.user_fullname}): super(key: key);
#override
_EditProfileState createState() => _EditProfileState();
}
Future<List<User>> getData() async {
var id = "26";
var url = baseurl + patientData + id;
var data;
var rest;
print('Calling uri: $url');
// 4
http.Response response = await http.get(url);
// 5
if (response.statusCode == 200) {
data = response.body;
print(data);
} else {
print(response.statusCode);
}
//Map<String, dynamic> user = jsonDecode(data);
var jsonData = jsonDecode(data.body);
List<User> users = [];
for (var u in jsonData) {
User user = User(u['fullname'], u['contactno'], u['address'], u['city'], u['gender'], u['email']);
users.add(user);
}
// print(users.length.toString);
}
I want to access the fullName from my above list in future function in Text widget where I have used snapshot.data.fullName below
class _EditProfileState extends State<EditProfile> {
#override
void initState() {
super.initState();
getData();
}
#override
Widget build(BuildContext context) {
getData().then((value) {
print(value);
});
return FutureBuilder(
future: getData(),
// ignore: missing_return
builder: (context, snapshot) {
if (snapshot.hasData) {
return WillPopScope(
onWillPop: () {},
child: Scaffold(
appBar: AppBar(title: Text("Your Profile"), automaticallyImplyLeading: false, actions: <Widget>[
IconButton(
icon: Icon(
Icons.logout,
color: Colors.white,
),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => PatientDashboard()));
},
)
]),
body: SingleChildScrollView(
child: Container(
// color: Colors.pink,
child: Column(
children: [
Center(
child: Padding(
padding: const EdgeInsets.only(top: 18.0),
child: Container(
// color: kPrimaryLightColor,
child: Stack(
children: [
//Image
CircleAvatar(
radius: 100,
backgroundColor: Colors.red[900],
child: CircleAvatar(
radius: 95,
backgroundImage: _pic == null ? AssetImage("assets/images/doctor2.jpg") : FileImage(_pic),
),
),
Positioned(
bottom: 5,
right: 15,
child: CircleAvatar(
backgroundColor: Colors.cyanAccent,
child: GestureDetector(
onTap: () {
setState(() {
//firstname = widget.user_fullname;
getImage();
state = 19;
});
},
child: Icon(Icons.camera_alt)),
radius: 20,
),
)
],
),
),
),
),
//Name
Container(
width: double.infinity,
//color: Colors.grey[400],
child: Stack(
children: [
Center(
child: Padding(
padding: const EdgeInsets.only(left: 18.0, top: 20),
child: Container(
//color: Colors.cyan[50],
width: MediaQuery.of(context).size.width * 0.78,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Name"),
Padding(
padding: const EdgeInsets.only(top: 2.0),
child: state == 1
? TextField(
decoration: InputDecoration(border: InputBorder.none, hintText: "${snapshot.data}", hintStyle: TextStyle(fontSize: 17, fontWeight: FontWeight.bold)), //style: TextStyle(under),
onChanged: (text) {
firstname = text;
},
)
: Text(
snapshot.data.fullName,
style: TextStyle(fontSize: 17, fontWeight: FontWeight.bold),
),
)],
else {
return Center(child: CircularProgressIndicator());
}
},
);
}
}
but I am getting this error
Error: NoSuchMethodError: 'body'
method not found
```
Arguments: []
at Object.throw_ [as throw] (http://localhost:59886/dart_sdk.js:5333:11)
at Object.defaultNoSuchMethod (http://localhost:59886/dart_sdk.js:5778:15)
at String.noSuchMethod (http://localhost:59886/dart_sdk.js:6878:19)
at Object.noSuchMethod (http://localhost:59886/dart_sdk.js:5774:30)
at Object.dload (http://localhost:59886/dart_sdk.js:5395:17)
at getData (http://localhost:59886/packages/newfypapproach/patient/screens/patientForgotPassword.dart.lib.js:12720:64)
at getData.next (<anonymous>)
at http://localhost:59886/dart_sdk.js:39031:33
at _RootZone.runUnary (http://localhost:59886/dart_sdk.js:38888:58)
at _FutureListener.thenAwait.handleValue (http://localhost:59886/dart_sdk.js:33874:29)
at handleValueCallback (http://localhost:59886/dart_sdk.js:34434:49)
at Function._propagateToListeners (http://localhost:59886/dart_sdk.js:34472:17)
at _Future.new.[_completeWithValue] (http://localhost:59886/dart_sdk.js:34314:23)
at async._AsyncCallbackEntry.new.callback (http://localhost:59886/dart_sdk.js:34337:35)
at Object._microtaskLoop (http://localhost:59886/dart_sdk.js:39175:13)
at _startMicrotaskLoop (http://localhost:59886/dart_sdk.js:39181:13)
at http://localhost:59886/dart_sdk.js:34688:9
```
I had used this different approach for creating a future function returning list of strings and the list was working perfectly having all values.
```
Future<List<String>> getData() async {
var id = "26";
var url = baseurl + patientData + id;
var data;
var rest;
print('Calling uri: $url');
// 4
http.Response response = await http.get(url);
// 5
if (response.statusCode == 200) {
data = response.body;
print(data);
// rest = data['result'] as List;
// print(rest);
//print(data);
} else {
print(response.statusCode);
}
Map<String, dynamic> user = jsonDecode(data);
// var name = user['result']['name'];
String fullName = user['result'][0][0];
String contactNo = user['result'][0][1];
String address = user['result'][0][2];
String city = user['result'][0][3];
String gender = user['result'][0][4];
String email = user['result'][0][5];
return <String>[fullName, contactNo, address, city, gender, email];
}
Change your getData as follows
Future<List<User>> getData() async {
var id = "26";
var url = baseurl + patientData + id;
Map<String, dynamic> data ={};
var rest;
// 4
http.Response response = await http.get(url);
// 5
if (response.statusCode == 200) {
data = response.body;
print(data);
} else {
print(response.statusCode);
}
//Map<String, dynamic> user = jsonDecode(data);
var jsonData = jsonDecode(data);
List<User> users = [];
for (var u in jsonData) {
User user = User(u['fullname'], u['contactno'], u['address'], u['city'], u['gender'], u['email']);
users.add(user);
}
return users; }

How to perform Pagination in Flutter

I have been going through various articles on pagination in flutter but none of them seem to work out for me. The API endpoint I am working with looks like this
http://camx.heropp.com/api/connect?offset=0 (this is an example link and so it won't work) while the response I get when I make the request looks like this
{
"result": {
"connectUsers": [
{
"_id": "5f6a412d2ea9350017bec99f",
"userProfile": {
"rep_points": 0.75,
"visits": 0,
"bio": "Nothing for you ",
"gender": "Male",
"university": "University Of Technology",
"avatar": "https://camx.heroapp.com/5f6a412d2ea9350017bec99f"
},
"name": "Joseph Henshaw ",
"userTag": "bigjo",
"id": "5f6a412d2ea9350017bec99f",
"sameCampus": true
},
{
"_id": "5f6bbf1cbd5faa00170d92b1",
"userProfile": {
"rep_points": 0,
"visits": 0
},
"name": "John Doe",
"userTag": "#doee",
"id": "5f6bbf1cbd5faa00170d92b1",
"sameCampus": false
}
]
}
}
what i am trying to achieve is paginate the data coming from the api..the offset begins at 0 and increases with 10, i.e to get more data 0ffset=20..30..and so on
This is the request I am making to get the JSON response shown above
Future<void> fetchConnect() async {
var uri = Uri.parse('http://campusx.herokuapp.com/api/v1/users/connect');
uri = uri.replace(query: 'offset=$offsetNumber');
print(uri);
try {
final response = await http.get(
uri,
headers: {
HttpHeaders.authorizationHeader: "Bearer $userToken",
},
);
// List<Photo> fetchedPhotos = Photo.parseList(json.decode(response.body));
if (response.statusCode == 200 || response.statusCode == 201) {
print("IT works")
} else {
print(response.statusCode);
}
List<ConnectUsers> fetchedConnects =
ConnectUsers.parseList(json.decode(response.body));
setState(() {
connectMore = fetchedConnects.length == defaultConnectsPerPageCount;
loading = false;
offsetNumber = offsetNumber + 10;
connects.addAll(fetchedConnects);
});
} catch (e) {
setState(() {
loading = false;
error = true;
});
}
}
and this is how my UI for displaying the data fetched(the widget getConnect is placed in the body of my Scaffold
Widget getConnects() {
if (connects.isEmpty) {
if (loading) {
return Center(
child: Padding(
padding: const EdgeInsets.all(8),
child: CircularProgressIndicator(),
));
} else if (error) {
return Center(
child: InkWell(
onTap: () {
setState(() {
loading = true;
error = false;
fetchConnects();
});
},
child: Padding(
padding: const EdgeInsets.all(16),
child: Text("Error while loading connects, tap to try again"),
),
));
}
} else {
return ListView.builder(
itemCount: connects.length + (connectMore ? 10 : 0),
itemBuilder: (context, index) {
if (index == connects.length - nextPageThreshold) {
fetchConnects();
}
if (index == connects.length) {
if (error) {
return Center(
child: InkWell(
onTap: () {
setState(() {
loading = true;
error = false;
fetchConnects();
});
},
child: Padding(
padding: const EdgeInsets.all(16),
child:
Text("Error while loading connects, tap to try agin"),
),
));
} else {
return Center(
child: Padding(
padding: const EdgeInsets.all(8),
child: CircularProgressIndicator(),
));
}
}
// final Photo photo = photos[index];
final ConnectUsers connect = connects[index];
return Card(
child: Column(
children: <Widget>[
// Image.network(
// connect.name.connectUsers[index].userProfile.avatar,
// fit: BoxFit.fitWidth,
// width: double.infinity,
// height: 160,
// ),
Padding(
padding: const EdgeInsets.all(16),
child: Text(connect.name,
// connect
// .result.connectUsers[index].userProfile.university,
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 16)),
),
],
),
);
});
}
return Container();
}
this is the error i get when using this code
The getter 'isEmpty' was called on null.
Receiver: null
Tried calling: isEmpty
Looks like you are calling connects.isEmpty in your widget but you didn't initialise connects -> connects is null so you get the error above.
You could do a null check or initialise connects
...
// initialise so connects is not null
connects = []
...
Widget getConnects() {
if (connects.isEmpty) {
if (loading) {
return Center(
(...)
Widget getConnects() {
// do a null check before calling member
if (connects == null || connects.isEmpty) {
if (loading) {
return Center(
(...)
I've solved the problem, this is the way i used
this is my model.dart class
import 'package:flutter/foundation.dart';
ConnectModel payloadFromJson(String str) =>
ConnectModel.fromJson(json.decode(str));
String payloadToJson(ConnectModel data) => json.encode(data.toJson());
class ConnectModel {
ConnectModel({
this.result,
});
Result result;
factory ConnectModel.fromJson(Map<String, dynamic> json) => ConnectModel(
result: Result.fromJson(json["result"]),
);
Map<String, dynamic> toJson() => {
"result": result.toJson(),
};
}
class Result {
Result({
this.connect,
});
List<Connect> connect;
factory Result.fromJson(Map<String, dynamic> json) => Result(
connect: List<Connect>.from(
json["connectUsers"].map((x) => Connect.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"connectUsers": List<dynamic>.from(connect.map((x) => x.toJson())),
};
}
class Connect with ChangeNotifier {
Connect({
this.id,
this.name,
this.userTag,
this.university,
this.checkIsFollowing,
this.avatar,
});
String name;
String userTag;
String id;
String university;
String avatar;
bool checkIsFollowing;
factory Connect.fromJson(Map<String, dynamic> json) => Connect(
id: json["_id"],
name: json["name"],
userTag: json["userTag"],
university: json["userProfile"]["university"],
checkIsFollowing: json["checkIsFollowing"],
avatar: json["userProfile"]["avatar"],
);
Map<String, dynamic> toJson() => {
"_id": id,
"name": name,
"userTag": userTag,
"userProfile"
"university": university,
"userProfile"
"avatar": avatar,
"checkIsFollowing": checkIsFollowing
};
}
this is my method, where offsetNumber is initialized to 0 by default
List<Connect> mainList = [];
List<String> nameList = [];
Future<List<Connect>> getConnectionsList(var offsetNumber) async {
var uri = "http://campusx.herokuapp.com/api/v1/users/connect?$offsetNumber";
var token = "pass_your_token_here";
try {
final response =
await http.get(uri, headers: {"Authorization": "Bearer $token"});
if (response.statusCode == 200) {
var data = json.decode(response.body);
var d = data['result']['connectUsers'];
for (var u in d) {
Connect c = Connect.fromJson(u);
mainList.add(c);
}
setState(() {
nameList = mainList.map((e) => e.name).toList();
//add other parameters gotten from the endpoint here, i used name only for test purposes
});
} else {
print(response.body);
}
} catch (e) {
print(e);
}
return mainList;
}
this is the ListView builder i displayed the names in
ListView.builder(
itemCount: mainList.length,
itemBuilder: (_, index) {
return Container(
height: 120,
child: Text(
nameList[index],
style: TextStyle(fontSize: 39),
),
);
},
)
then either onClick or a button or when the list hits the bottom of your phone screen, you'd setState (() {}); and increase the size of the offsetNumber. Something like this:
setState(() {
offsetNumber = offsetNumber + 10;
future = getConnectionsList(offsetNumber);
});