setState the showDialog() from outside flutter - 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);
}
);

Related

data did not display in the pie chart

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();
},
),
),

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 bloc doesn't showing UI as per proper state

Am using flutter bloc library and maintaining simple process for as per library for state management. In this code I am getting the state as expected but UI is not updating, its always returning the default state ui which a circle spinner . I have checked the state using bloc observer too. So need to know that what I have done wrong and need suggestions on that.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: buildAppBar(context),
body: Column(
children: [
BlocBuilder<UserManageCubit, UserManageState>(
builder: (context, state) {
if (state is Initial) {
return const Center(
child: CircularProgressIndicator(
color: Colors.red,
));
}
if (state is UserDetailFetched) {
Column(
children: <Widget>[
Text(
'${state.userDetails.name}'.toUpperCase(),
style: kNavyTextStyleNormal.copyWith(
fontSize: 18.sp,
),
),
Text(
'${state.userDetails.email}',
style: kNavyTextStyleNormal.copyWith(
fontWeight: FontWeight.bold,
),
),
Text(
'${state.userDetails.phone}',
style: kNavyTextStyleNormal.copyWith(
fontWeight: FontWeight.bold,
),
),
Text(
'Registered on ${DateTimeUtils.format(
DateTimeUtils.fromString(state.userDetails.createdAt!),
).split("-")[0]}',
style: kNavyTextStyleNormal.copyWith(
fontWeight: FontWeight.bold,
color: go11ThemeGreen,
),
),
SizedBox(height: 16.h),
],
);
}
return CircularProgressIndicator(
color: Colors.amber,
);
},
),
],
),
);
}
Calling bloc
#override
void initState() {
BlocProvider.of<UserManageCubit>(context).getUserDetails(widget.userId);
super.initState();
}
#Cubit impl
UserManageCubit({required this.userManageRepo})
: super(const UserManageState.initial());
void getUserDetails(int userId) async {
final FormData formData = FormData.fromMap({
'user_id': userId,
});
final Either<Failure, UserDetailsResponse> userDetailResponseEither =
await userManageRepo.getUserDetails(formData);
emit(const UserManageState.loading());
userDetailResponseEither.fold(
(failure) => {
emit(
UserManageState.loadFailure(
errorObject:
ErrorObject.mapFailureToErrorObject(failure: failure),
),
)
},
(response) => {
emit(
UserManageState.userDetailFetched(
userDetails: response.userDetails),
),
});
}
#state class
#freezed
class UserManageState with _$UserManageState {
const factory UserManageState.initial() = Initial;
const factory UserManageState.loading() = Loading;
const factory UserManageState.loadFailure({
required ErrorObject errorObject,
}) = LoadFailure;
const factory UserManageState.userDetailFetched(
{required UserDetails userDetails,
#Default(0) int currentDocType,
#Default(0) int currentCancelType}) = UserDetailFetched;
}
You are not returning your column
if (state is UserDetailFetched) {
return Column(
children: <Widget>[
Text(
'${state.userDetails.name}'.toUpperCase(),
style: kNavyTextStyleNormal.copyWith(
fontSize: 18.sp,
),
),
Text(
'${state.userDetails.email}',
style: kNavyTextStyleNormal.copyWith(
fontWeight: FontWeight.bold,
),
),
Text(
'${state.userDetails.phone}',
style: kNavyTextStyleNormal.copyWith(
fontWeight: FontWeight.bold,
),
),
Text(
'Registered on ${DateTimeUtils.format(
DateTimeUtils.fromString(state.userDetails.createdAt!),
).split("-")[0]}',
style: kNavyTextStyleNormal.copyWith(
fontWeight: FontWeight.bold,
color: go11ThemeGreen,
),
),
SizedBox(height: 16.h),
],
);
}

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.

How can display two buttons dynamically based on an if condition in flutter

I am new to flutter and I am having a difficult challenge to perform two if conditions. All I want to achieve is to perform an if statement on two boolean conditions in the the array below. I want to check if Success == true && Stock['Submitted'] == true, then its should display a button labelled "Validate farmers" but if these two conditions did not hold true then it should show a button labelled "Take Inventory". But its not working. Please how can i access the Submitted Value?
this is the structure of the arry:
{
"StatusCode": 200,
"Message": "Record Found",
"Success": true,
"Stock": {
"Oid": 30,
"CreatedBy": "johndoh",
"CreatedOn": "2020-07-07T10:28:19.09",
"ModifiedBy": null,
"ModifiedOn": null,
"Season": null,
"SeasonTitle": null,
"Anchor": 11,
"AnchorName": null,
"AnchorAcronym": null,
"DistributionCentre": 11,
"DistributionCentreName": null,
"Agent": "John Doh",
"StateCoordinator": "Godwin Obute",
"StockDate": "2020-07-07T10:27:49.03",
"TransId": "20200707102819089",
"StateCoordinatorId": "38",
"AgentId": "57",
"UserId": "b6caf34c-a425-4710-a3ee-aa22a382882a",
"Submitted": false,
"SubmittedOn": null,
"SubmittedBy": null,
"StockItems": []
}
}
A Function that calls the http request which returns the array above just after my stateful widget state:
var user;
var userData;
var userDetail;
var anchors;
var dailyStatus;
var dailyStocks;
var found = false;
var stockoid;
// var dataSubmitted = false;
#override
void initState() {
_getUserInfo();
super.initState();
}
//This getuser info gives me the parameters to use on the checkinventorystatus
void _getUserInfo() async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
var userJson = localStorage.getString('loginRes');
user = json.decode(userJson);
userDetail = user['UserDetail'];
print('${userDetail['Oid']} poii'); //Just to get the userId
anchors = user['Anchors'];
setState(() {
userData = user;
print('${userData['UserId']} ioo');
// var dc = value['DistributionCentres'][1]['Oid'];
// print(dc);
});
}
//This is the main function that gives me the array above
Future<CheckInventoryStatus> checkDailyStatus() async {
final response = await http.get(
'http://api.ergagro.com:112/CheckDailyStockTakingStatus?userId=${userData['UserId']}&agentId=${userDetail['Oid']}',
headers: {
'Content-type': 'application/json',
'Accept': 'application/json',
});
if (response.statusCode == 200) {
found = true;
final jsonStatus = jsonDecode(response.body);
var stock = jsonStatus['Stock'];
bool submitted = stock['Submitted'];
stockoid = stock['Oid'].toString();
setState(() {
found = submitted;
});
return CheckInventoryStatus.fromJson(jsonStatus);
} else {
throw Exception();
}
}
This is my Widget View:
after my children widget:
Row(
children: <Widget>[
/////////// Based on the response I want to use it to control these two buttons below
///if the response is 200 it should display validate farmer else it should display Take Inventory/////////////
Padding(
padding: const EdgeInsets.all(10.0),
//this is where I want to perform the check but its not working
// dailyStatus['StatusCode'] == 200
child: found
? FlatButton(
child: Padding(
padding: EdgeInsets.only(
top: 8, bottom: 8, left: 10, right: 10),
child: Text(
'Validate Farmers',
textDirection: TextDirection.ltr,
style: TextStyle(
color: Colors.white,
fontSize: 15.0,
decoration: TextDecoration.none,
fontWeight: FontWeight.normal,
),
),
),
color: Colors.green,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(20.0)),
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => StartScanPage()));
// Edit()was here
},
)
//if the status is not 200 then it should allow an agent to take inventory
: FlatButton(
child: Padding(
padding: EdgeInsets.only(
top: 8, bottom: 8, left: 10, right: 8),
child: Text(
'Take Inventory',
textDirection: TextDirection.ltr,
style: TextStyle(
color: Colors.white,
fontSize: 15.0,
decoration: TextDecoration.none,
fontWeight: FontWeight.normal,
),
),
),
color: Colors.blueGrey,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(20.0)),
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => StockInventoryPage(
userData['UserId'],
'${userDetail['Oid']}',
'${value['DistributionCentres'][i]['Oid']}',
stockoid)));
},
),
),
/////////// End of Buttons /////////////
],
),
How about Something like this:
Widget _showButton(bool firstCondition, bool seacondCondition) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: FlatButton(
child: Padding(
padding: EdgeInsets.only(top: 8, bottom: 8, left: 10, right: 10),
child: Text(
(firstCondition && seacondCondition)?'Validate Farmers':'Take Inventory',
textDirection: TextDirection.ltr,
style: TextStyle(
color: Colors.white,
fontSize: 15.0,
decoration: TextDecoration.none,
fontWeight: FontWeight.normal,
),
),
),
color: Colors.green,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(20.0)),
onPressed: () {
if(firstCondition && seacondCondition)
Navigator.push(context,
new MaterialPageRoute(builder: (context) => StartScanPage()));
else
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) =>
StockInventoryPage(
userData['UserId'],
'${userDetail['Oid']}',
'${value['DistributionCentres'][i]['Oid']}',
stockoid)));
// Edit()was here
},
));
}
then simply put _showButton inside your children widget