data did not display in the pie chart - flutter

here are my function name fetchPrayerData() and inside the function i want to count the data how many subuh that are "Prayed On Time, "Prayed Late", and "Not Prayed" and display the data in the pie chart but, unfortunately the data count won't display in the pie chart although there is no error in the code.
Future<List<PieChartSectionData>> fetchPrayerData() async {
double subuhPrayed = 0;
double subuhPrayedLate = 0;
double subuhNotPrayed = 0;
// subuhPrayed = prayedOnTimeQuerySnapshot.docs.length.toDouble();
// subuhPrayedLate = prayedLateQuerySnapshot.docs.length.toDouble();
// subuhNotPrayed = notPrayedQuerySnapshot.docs.length.toDouble();
FirebaseFirestore.instance
.collection('record_prayer')
.where('prayerName', isEqualTo: 'subuh')
.where('dailyPrayerStatus', isEqualTo: 'Prayed On Time')
.count()
.get()
.then((querySnapshot) => subuhPrayed = querySnapshot.count.toDouble());
FirebaseFirestore.instance
.collection('record_prayer')
.where('prayerName', isEqualTo: 'subuh')
.where('dailyPrayerStatus', isEqualTo: 'Prayed Late')
.count()
.get()
.then(
(querySnapshot) => subuhPrayedLate = querySnapshot.count.toDouble());
FirebaseFirestore.instance
.collection('record_prayer')
.where('prayerName', isEqualTo: 'subuh')
.where('dailyPrayerStatus', isEqualTo: 'Not Prayed')
.count()
.get()
.then((querySnapshot) => subuhNotPrayed = querySnapshot.count.toDouble());
return [
PieChartSectionData(
color: Colors.green,
value: subuhPrayed,
//title: '$prayedOnTimeQuerySnapshot',
title: '${(subuhPrayed * 100).toStringAsFixed(0)}%',
radius: 60,
titleStyle: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
PieChartSectionData(
color: Colors.yellow,
value: subuhPrayedLate,
//title: '',
title: '${(subuhPrayedLate * 100).toStringAsFixed(0)}%',
radius: 60,
titleStyle: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
PieChartSectionData(
color: Colors.red,
value: subuhNotPrayed,
title: '${(subuhNotPrayed * 100).toStringAsFixed(0)}%',
radius: 60,
titleStyle: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
];
}
here are the stateful widget that i want to display the data in the pie chart but, it wont display the data that count from the function.
Expanded(
child: FutureBuilder<
List<PieChartSectionData>>(
future: fetchPrayerData(),
builder: (context, snapshot) {
if (snapshot.hasData &&
snapshot.data != null) {
return AspectRatio(
aspectRatio: 1,
child: PieChart(
PieChartData(
pieTouchData: PieTouchData(
touchCallback: (FlTouchEvent
event,
pieTouchResponse) {},
),
borderData: FlBorderData(
//show: false;
),
sectionsSpace: 0,
centerSpaceRadius: 40,
sections: snapshot.data!,
),
),
);
}
return const CircularProgressIndicator();
},
),
),

Related

purchasing consumable item using flutter_inapp_purchase?

I am trying to make an in app purchase function,
and I faced this error: "you already own this item".
I found out that this is because the store considers the item as non-consumable item.
Unlike in_app_purchase package, this package doesn't support buyConsumable and buyNonConsumable functions.
so how to execute purchasing consumable item using that package?
also I assume that this is because of what's said above
items that are purchased keep being refunded automatically.
anyway my code is based on their example code but there it is:
storeController.dart
late StreamSubscription purchaseUpdatedSubscription;
late StreamSubscription purchaseErrorSubscription;
late StreamSubscription connectionSubscription;
// just followed the example
final List<String> productLists = Platform.isAndroid
? [
'point1',
'point2',
'point3',
]
: [
'point1',
'point2',
'point3'
];
String platformVersion = Platform.operatingSystem;
RxList<IAPItem> itemsList = <IAPItem>[].obs;
RxList<PurchasedItem> purchasesList = <PurchasedItem>[].obs;
#override
void onInit() async {
init();
await initPlatformState();
await getProduct();
await getPurchaseHistory();
}
Future<void> initPlatformState() async {
// Platform messages may fail, so we use a try/catch PlatformException.
// prepare
var result = await FlutterInappPurchase.instance.initialize();
print('result: $result');
// refresh items for android
try {
String msg = await FlutterInappPurchase.instance.consumeAll();
print('consumeAllItems: $msg');
} catch (err) {
print('consumeAllItems error: $err');
}
connectionSubscription =
FlutterInappPurchase.connectionUpdated.listen((connected) async {
print('connected: $connected');
});
purchaseUpdatedSubscription =
FlutterInappPurchase.purchaseUpdated.listen((productItem) async {
print('purchase-updated: $productItem');
await getPurchaseHistory();
});
purchaseErrorSubscription =
FlutterInappPurchase.purchaseError.listen((purchaseError)async {
print('purchase-error: $purchaseError');
});
}
Future getProduct() async {
List<IAPItem> items =
await FlutterInappPurchase.instance.getProducts(productLists);
for (var item in items) {
print('${item.toString()}');
itemsList.add(item);
}
}
Future getPurchaseHistory() async {
List<PurchasedItem>? items =
await FlutterInappPurchase.instance.getPurchaseHistory();
for (var item in items!) {
print('${item.toString()}');
purchasesList.add(item);
}
}
and the productListWidget:
Widget productList(context) {
return GridView.builder(
shrinkWrap: true,
itemCount: controller.itemsList.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
mainAxisExtent: Get.width * 0.4 + 70,
),
itemBuilder: (BuildContext context, int index) {
final item = controller.itemsList[index];
return
Container(
width: Get.width * 0.5,
alignment: Alignment.center,
color: Colors.transparent,
margin: const EdgeInsets.fromLTRB(10,0,10,0),
child: Stack(
children: [
Container(
color: const Color(0xff353535),
child: Column(
children: [
const SizedBox(height: 10),
const Text('Name', style: TextStyle(color: Colors.white)),
Text(
item.title ?? '',
style: const TextStyle(
color: Colors.white,
fontSize: 15,
fontWeight: FontWeight.w600,
fontStyle: FontStyle.normal,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 10),
const Text('Desc', style: TextStyle(color: Colors.white)),
Text(
item.description ?? '',
style: const TextStyle(
color: Colors.grey,
fontSize: 13,
fontStyle: FontStyle.normal,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 10),
const Text('Price', style: TextStyle(color: Colors.white)),
Text(
'${item.currency ?? ''} ${item.originalPrice}',
style: const TextStyle(
color: Colors.white,
fontSize: 12,
fontStyle: FontStyle.normal,
overflow: TextOverflow.ellipsis
)
),
const SizedBox(height: 10),
GestureDetector(
onTap: () async {
controller.requestPurchase(item);
},
child: Container(
alignment: Alignment.center,
width: 100,
height: 30,
color: const Color(0xffE1FD2E),
child: const Text('Purchase')
)
)
]
),
),
]
)
);
}
);
}

Flutter Firestore error adding value to value from Firestore

I've got an error while i tried to add value to value from firestore.
I want to sum value from kcal variable with firestore "progress" value
progressAdd = nutr + kcal2;
Error screenshot
Future addMeal() async {
var nutr;
await FirebaseFirestore.instance
.collection('usersData')
.doc(FirebaseAuth.instance.currentUser!.uid)
.get()
.then((doc) => {nutr = doc.data()});
print('test');
if (nutr != null) {
this.progress = nutr['progress'];
setState(() {
progressAdd = nutr + kcal2;
FirebaseFirestore.instance
.collection('usersData')
.doc(FirebaseAuth.instance.currentUser!.uid)
.update({'progress': progressAdd});
});
} else {
print('test2');
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
backgroundColor: mainFontColor().tsubColor,
title: Text(
':/',
textAlign: TextAlign.center,
style: GoogleFonts.lato(
fontWeight: FontWeight.w600, color: Colors.white),
),
content: Container(
height: 120,
width: 250,
child: Column(children: [
Text(
'Something went wrong!',
style: GoogleFonts.dosis(color: Colors.white),
),
SizedBox(
height: 5,
),
Text(
'Go back and try again!',
style: GoogleFonts.dosis(color: Colors.white),
),
SizedBox(
height: 20,
),
Container(
height: 40,
width: 180,
child: ElevatedButton(
child: Text('OK'),
style: ElevatedButton.styleFrom(
backgroundColor: mainFontColor().tsubColor2),
onPressed: (() => Navigator.pop(context))),
)
]),
),
);
});
}
}
This line:
.then((doc) => {nutr = doc.data()});
will assign the doc.data() which have a type of Map<String, dynamic> to the nutr variable.
so, this:
progressAdd = nutr + kcal2;
is actually not valid, because you want to make an addition over objects that can't be summed, nutr have a type of Map<String, dynamic> and kcal2 is double.
from the code I read, I assume that you want to get the existing progress on the Firestore document and update it with the sum of it + kcal2, so try the following:
instead of:
progressAdd = nutr + kcal2;
replace with this:
progressAdd = this.progress + kcal2;
this now should be valid that you want to sum to numbers the update in Firestore.

Flutter error : Expected a value of type 'String', but got one of type 'List<dynamic>'

Im new to Stack overflow and this is my first question. Apologies if I'm asking the wrong way. I am trying to stream data from firebase to show in DataTable but I'm getting an error. Help would be appreciated.
Below is my code:
Container(
child: ListView(
shrinkWrap: true,
padding: const EdgeInsets.all(16),
children: [
Container(
color: kDarkBlackColor,
child: new StreamBuilder<QuerySnapshot>(
stream: _movieStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData || snapshot.data.docs == null)
{
print("no Data");
return LinearProgressIndicator();
}
else if (snapshot.data.docs.length > 0) {
print("Has Data");
return DataTable(
columns: [
DataColumn(
label: Text('Prev',
style: TextStyle(
fontSize: 18,
color: kBgColor,
fontWeight:
FontWeight.bold)
),
),
DataColumn(
label: Text('No.',
style: TextStyle(
fontSize: 18,
color: kBgColor,
fontWeight:
FontWeight.bold))),
DataColumn(
label: Text('Name',
style: TextStyle(
fontSize: 18,
color: kBgColor,
fontWeight:
FontWeight.bold))),
DataColumn(
label: Text('Genre',
style: TextStyle(
fontSize: 18,
color: kBgColor,
fontWeight:
FontWeight.bold))),
],
rows:
_buildList(context, snapshot.data.docs),
);
}
},
),
),
],
),
),
List<DataRow> _buildList(
BuildContext context, List<DocumentSnapshot> snapshot) {
return snapshot.map((data) => _buildListItem(context, data)).toList();
}
DataRow _buildListItem(BuildContext context, DocumentSnapshot data) {
final record = Record.fromSnapshot(data);
print("last");
return DataRow(cells: [
DataCell(
Container(width: 80, child: Image.asset('assets/images/movie1.png'))),
DataCell(Text(record.movieName)),
DataCell(Text(record.movieRating)),
DataCell(Text(record.movieGenre)),
]);
}
class Record {
final String movieName;
final String movieGenre;
final String movieRating;
final DocumentReference reference;
Record.fromMap(Map<String, dynamic> map, {this.reference})
: assert(map['movieName'] != null),
assert(map['movieGenre'] != null),
assert(map['movieRating'] != null),
movieName = map['movieName'],
movieGenre = map['movieGenre'],
movieRating = map['movieRating'];
Record.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data(), reference: snapshot.reference);
#override
String toString() => "Record<$movieName:$movieRating:$movieGenre>";
}
After I run my code I get " Expected a value of type 'String', but got one of type 'List' ".
I think the code stops around "return snapshot.map((data) => _buildListItem(context, data)).toList();"

Navigating to another page in Stream Builder only once if stream of data is coming

I am using Stream builder to receive data from Esp32 BLE to my Flutter Application, I am detecting seizures in my app so I have used a condition of currentValue = 2 if a seizure occurs and navigate to the other page. But the other page is called many times until the current value = 2 stops coming.
How can I call the page only one time if the condition satisfies and the value '2' keeps coming?
This is my code of Stream Builder where page is called when current Value becomes 2:
StreamBuilder<List<int>>(
stream: stream,
initialData: lastValue,
builder: (BuildContext context,
AsyncSnapshot<List<int>> snapshot) {
if (snapshot.hasError)
return Text(
'Error: ${snapshot.error}',
style: TextStyle(
fontFamily: 'SF Pro Display',
fontSize: 19,
color: const Color(0xffffffff),
fontWeight: FontWeight.w500,
height: 1.4736842105263157,
),
);
if (snapshot.connectionState ==
ConnectionState.active) {
//var currentValue = _dataParser(snapshot.data);
var currentVal =
snapshot.data.toString();
int currentValue = int.parse(
currentVal.substring(
1, currentVal.length - 1),
onError: (source) => -1); // 33
print("String data $currentValue");
if (currentValue == 2) {
return FutureBuilder(
future: Future.delayed(
const Duration(seconds: 0),
() async {
Seziurealert();
}
),
builder: (context, snapshot) {
// setState(() {
// currentValue = 0;
// });
return Text(
'Seizure Occurred',
style: TextStyle(
fontFamily: 'SF Pro Display',
fontSize: 19,
color: const Color(0xffffffff),
fontWeight: FontWeight.w500,
height: 1.4736842105263157,
),
);
});
} else if (currentValue == 0) {
return Text(
'Device not calibrated',
style: TextStyle(
fontFamily: 'SF Pro Display',
fontSize: 19,
color: const Color(0xffffffff),
fontWeight: FontWeight.w500,
height: 1.4736842105263157,
),
);
} else if (currentValue == 1) {
return Text(
'$currentValue',
style: TextStyle(
fontFamily: 'SF Pro Display',
fontSize: 19,
color: const Color(0xffffffff),
fontWeight: FontWeight.w500,
height: 1.4736842105263157,
),
);
}
return Text(
'$currentValue',
style: TextStyle(
fontFamily: 'SF Pro Display',
fontSize: 19,
color: const Color(0xffffffff),
fontWeight: FontWeight.w500,
height: 1.4736842105263157,
),
);
} else {
return Text(
'Check the stream',
style: TextStyle(
fontFamily: 'SF Pro Display',
fontSize: 19,
color: const Color(0xffffffff),
fontWeight: FontWeight.w500,
height: 1.4736842105263157,
),
);
}
},
),
Seizure Alert function:
Seziurealert(){
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) {
return TriggeringAlert(
device:
widget.device);
},
),
(route) => false,
);
}
I also tried using this but the same was happening as it is with Future Builder:
SchedulerBinding.instance.addPostFrameCallback((_) {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) {
return TriggeringAlert(
device:
widget.device);
},
),
(route) => false,
);
This is the image of my page that is called when Value 2 occurs. This page keeps on showing until 10s of timer are over or I press the cancel button. But in my case even if the timer's 10 seconds are over the page is called again OR if I press the cancel button, the page is also called again in that case.
Please help me how can I avoid that as I am new to Flutter
Instead of using a Stream, you can use a Future. For example, you can use Stream.firstWhere to get a Future that will complete only when a specific predicate is met.
In your case, it would be something like:
final future = stream.map((value) {
final currentVal = value.toString();
final currentParsedVal = int.parse(
currentVal.substring(1, currentVal.length - 1),
onError: (source) => -1,
);
print("String data $currentParsedVal");
return currentParsedVal;
}).firstWhere((value) => value == 2);
Then, you can wait for this future and navigate to wherever you want when it's complete in your initState, for example.

setState the showDialog() from outside flutter

I need to setState the showDialog() from the outside. The showDialog() shows how many images are uploaded to Firestore. But setState is not working because it doesn't change the state of showDialog(). Is there any way to change the state of showDialog() from outside??
Here is my code.
Future<void> _upload() async {
Reference storageReference;
showDialog(
context: context,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
side: BorderSide(width: 1, color: Colors.white),
),
contentPadding: EdgeInsets.all(20),
content: SizedBox(
height: 150,
width: 180,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SpinKitRing(
color: Color(0xff43b0e2),
lineWidth: 10,
size: 100,
),
// here is the part I want to setState
Text("$value/${widget.imagelist.length + 1}",
style: TextStyle(
color: Color(0xff43b0e2),
fontWeight: FontWeight.w800,
fontFamily: "Montserrat",
fontStyle: FontStyle.normal,
fontSize: 18.0),
textAlign: TextAlign.center),
],
),
),
backgroundColor: Colors.grey.withOpacity(0.9),
);
},
);
for (File image in widget.imagelist) {
storageReference = FirebaseStorage.instance.ref().child('project/' +
FirebaseAuth.instance.currentUser.uid +
"/" +
widget.title +
"/" +
image.path.toString().split("/").last);
await storageReference.putFile(image);
String downloadURL = await storageReference.getDownloadURL();
setState(() {
imglist.add(downloadURL);
value += 1;
});
}
storageReference = FirebaseStorage.instance.ref().child('project/' +
FirebaseAuth.instance.currentUser.uid +
"/" +
widget.title +
"/thumbnail");
await storageReference.putFile(widget.thumbnail);
String thumbnailURL = await storageReference.getDownloadURL();
setState(() {
value += 1;
});
await FirebaseFirestore.instance.collection('Gallery').add({
"author": FirebaseAuth.instance.currentUser.uid,
"bookmark": <String>[],
"description": widget.description,
"image": imglist,
"liked": <String>[],
"time": Timestamp.fromDate(DateTime.now()),
"title": widget.title,
"visited": 0,
"is18": widget.is18,
"object": widget.objlist,
"tool": widget.toollist,
"thumbnail": thumbnailURL,
"tag": widget.taglist,
"platform": widget.platform,
});
Navigator.of(context).pop();
}
use valueNotifier
when image uploaded make notifier.value++;
and in showDialog add widget :
ValueListenableBuilder<int>(
valueListenable:notifier,
builder:(ctx,value,child){
return Text("$value/${widget.imagelist.length + 1}",
style: TextStyle(
color: Color(0xff43b0e2),
fontWeight: FontWeight.w800,
fontFamily: "Montserrat",
fontStyle: FontStyle.normal,
fontSize: 18.0),
textAlign: TextAlign.center);
}
);