Related
This is my UI
In this, I used a date picker and in there shows "Birthday" word as an initial date, when the click selects the button then shows the dates, That works perfectly. But I wanna add shared Preferences to this When added that, after the selected word and close the app and reopened again then should show the date that is selected at the last.
EX:- When the user at the first time open the app then should show like this
and h or she select "2021/4/27" and after close app and reopening then should display
For that I tried and I added shared preferences but when I add declared variable as initial value then shows this error.
My code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class BirthdayScreen extends StatefulWidget {
const BirthdayScreen({Key? key}) : super(key: key);
#override
State<BirthdayScreen> createState() => _BirthdayScreenState();
}
class _BirthdayScreenState extends State<BirthdayScreen> {
// 1st dropdown button
#override
void initState() {
super.initState();
dropdownValueBirthday = birthday.first;
checkValueBirthday();
}
//date picker
DateTime? selectedDate;
DateTime now = new DateTime.now();
void showDatePicker() {
DateTime mindate = DateTime(now.year - 2, now.month, now.day - 29);
DateTime maxdate = DateTime(now.year - 1, now.month, now.day);
showCupertinoModalPopup(
context: context,
builder: (BuildContext builder) {
return Container(
height: MediaQuery.of(context).copyWith().size.height * 0.25,
color: Colors.white,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.date,
initialDateTime: mindate,
onDateTimeChanged: (value) {
if (value != null && value != selectedDate) {
setState(() {
selectedDate = value;
});
}
},
maximumDate: maxdate,
minimumDate: mindate,
),
);
});
}
String? dropdownValueBirthday;
List<String> birthday = [
'Birthday',
];
//IF "dropdownValueMembers" is empty pass "which" word as a initial value if al ready selected then pass the shared preference value
checkValueBirthday() {
_getDataBirthday();
}
_saveDataBirthday(String dropdownValueBirthdayShared) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
sharedPreferences.setString("dataBirthday", dropdownValueBirthdayShared);
}
_getDataBirthday() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
dropdownValueBirthday =
sharedPreferences.getString("dataBirthday") ?? birthday.first;
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Column(
children: [
Center(
child: Padding(
padding: const EdgeInsets.only(left: 15, top: 100),
child: Row(
children: <Widget>[
const Icon(
Icons.brightness_1,
color: Colors.black,
size: 10,
),
const Padding(
padding: EdgeInsets.only(left: 15.0),
child: Text("birthday",
style: TextStyle(
fontSize: 16.0,
)),
),
Padding(
padding: const EdgeInsets.only(left: 25.0),
child: SizedBox(
width: 110.0,
height: 25.0,
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
child: Center(
child: Text(
selectedDate == null
? (dropdownValueBirthday ?? birthday.first)
: '${selectedDate?.year}/${selectedDate?.month}/${selectedDate?.day} ',
style: const TextStyle(
fontSize: 16, fontWeight: FontWeight.w500),
),
),
),
),
),
Padding(
padding: const EdgeInsets.only(left: 15.0, top: 30.0),
child: SizedBox(
width: 88.0,
height: 25.0,
child: MaterialButton(
onPressed: showDatePicker,
shape: const StadiumBorder(),
color: Colors.blue,
child: const Text(
'select',
style: TextStyle(color: Colors.white, fontSize: 12),
),
),
),
),
],
),
),
),
Padding(
padding: const EdgeInsets.only(
bottom: 0.0,
),
child: SizedBox(
width: 160.0,
height: 35.0,
child: ElevatedButton(
style: ButtonStyle(
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
side: const BorderSide(
color: Colors.blueAccent,
),
),
),
),
onPressed: () {
_saveDataBirthday(dropdownValueBirthday!);
// _saveDataAgree(isChecked!);
},
child: const Text('next')),
),
),
],
),
),
);
}
}
How to solve this error and do shared Preference?
birthday is a List<String> and Text Widget only accepts String
I believe you need to do this
selectedDate == null
? (dropdownValueBirthday ?? birthday.first)
:'${selectedDate?.year}/${selectedDate?.month}/${selectedDate?.day} ',
Also you need to update the dropdownValueBirthday
onDateTimeChanged: (value) {
if (value != selectedDate) {
setState(() {
selectedDate = value;
dropdownValueBirthday = '${selectedDate?.year}/${selectedDate?.month}/${selectedDate?.day} ';
});
}
},
_saveDataBirthday(dropdownValueBirthday!.toString());
make sure this is string
This is my output
all these functions are works excellent. But I tried to add sharedPrefence to these dropdowns, select birthday and to the checkbox. But both dropdowns work perfectly, When I select something in the dropdown and click the next button and close the app and reopen again then shows the words that are selected at the last. But after that, I tried to add sharedPrefence to datePicker and thin "Are you agree " check box but then shows some errors. I have no idea how to solve that.
EX:- In this, I used a date picker, Agree checkbox and in there shows "Birthday" word as an initial date and check box is unselecting, when the click selects the button then shows the dates and pick date and can select check box then value is true, That works perfectly. But I wanna add shared Preferences to this When added that, after the selected word and close the app and reopened again then should show the date and check box value true that is selected at the last.
my full code.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class FamilyDetailsScreen extends StatefulWidget {
#override
State<FamilyDetailsScreen> createState() => _FamilyDetailsScreenState();
}
class _FamilyDetailsScreenState extends State<FamilyDetailsScreen> {
// 1st dropdown button
#override
void initState() {
super.initState();
dropdownValueMembers = items.first;
dropdownValueNumber = number.first;
dropdownValueBirthday = birthday.first;
dropdownValueBirthday = Agree.first;
checkValueMembers();
checkValueNumber();
checkValueBirthday();
checkValueAgree();
}
String? dropdownValueMembers;
// List of items in our dropdown menu
List<String> items = [
'howmany',
'one',
'two',
'three ',
'four',
'5 or more'
];
checkValueMembers() {
_getData();
}
_saveData(String dropdownValueMembersShared) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
sharedPreferences.setString("data", dropdownValueMembersShared);
}
_getData() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
dropdownValueMembers = sharedPreferences.getString("data") ?? items.first;
setState(() {});
}
// 2nd dropdown button
// data which child
String? dropdownValueNumber;
// // List of items in our dropdown menu
List<String> number = ['which', '1 st', '2 nd', '3 rd ', '4 th ', '5 th'];
//IF "dropdownValueMembers" is empty pass "which" word as a initial value if al ready selected then pass the shared preference value
checkValueNumber() {
_getDataNumber();
}
_saveDataNumbers(String dropdownValueNumberShared) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
sharedPreferences.setString("data2", dropdownValueNumberShared);
}
_getDataNumber() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
dropdownValueNumber = sharedPreferences.getString("data2") ?? number.first;
setState(() {});
}
//date picker
DateTime? selectedDate;
DateTime now = new DateTime.now();
void showDatePicker() {
DateTime mindate = DateTime(now.year - 2, now.month, now.day - 29);
DateTime maxdate = DateTime(now.year - 1, now.month, now.day);
showCupertinoModalPopup(
context: context,
builder: (BuildContext builder) {
return Container(
height: MediaQuery.of(context).copyWith().size.height * 0.25,
color: Colors.white,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.date,
initialDateTime: mindate,
onDateTimeChanged: (value) {
if (value != null && value != selectedDate) {
setState(() {
selectedDate = value;
});
}
},
maximumDate: maxdate,
minimumDate: mindate,
),
);
});
}
String? dropdownValueBirthday;
List<String> birthday = [
'Birthday',
];
//sharedPreferences birthday
checkValueBirthday() {
_getDataBirthday();
}
_saveDataBirthday(String dropdownValueBirthdayShared) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
sharedPreferences.setString("dataBirthday", dropdownValueBirthdayShared);
}
_getDataBirthday() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
dropdownValueBirthday =
sharedPreferences.getString("dataBirthday") ?? birthday.first;
setState(() {});
}
//////////////////////////////////
// are you agree button
//boolean value (are you agree)
bool isChecked = false;
checkValueAgree() {
_getDataAgree();
}
_saveDataAgree(String dropdownValueAgreeShared) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
sharedPreferences.setBool("Agree", dropdownValueAgreeShared);
}
_getDataAgree() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
dropdownValueNumber = sharedPreferences.getBool("Agree") ?? isChecked.first;
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
resizeToAvoidBottomInset: false,
body: SafeArea(
child: Column(
children: <Widget>[
const Text(
'family details',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontSize: 18.00,
fontWeight: FontWeight.w700,
),
),
const SizedBox(
height: 30,
),
Padding(
padding: const EdgeInsets.only(top: 10, left: 15),
child: Row(
children: <Widget>[
const Icon(
Icons.brightness_1,
color: Colors.black,
size: 10.0,
),
const Padding(
padding: EdgeInsets.only(left: 13),
child: Text(
"Number of children",
style:
TextStyle(fontSize: 15, fontWeight: FontWeight.w600),
),
),
],
),
),
const SizedBox(
height: 25,
),
Row(
children: [
Padding(
padding: const EdgeInsets.only(left: 2),
child: Container(
height: 25,
decoration: BoxDecoration(
boxShadow: const <BoxShadow>[
//apply shadow on Dropdown button
BoxShadow(
color: Color.fromRGBO(
0, 0, 0, 0.37), //shadow for button
blurRadius: 5) //blur radius of shadow
],
color: Colors.white,
borderRadius: BorderRadius.circular(15),
),
child: DropdownButton(
underline: Container(),
borderRadius: BorderRadius.circular(20),
// Initial Value
value: dropdownValueMembers,
// Down Arrow Icon
icon: const Icon(Icons.keyboard_arrow_down),
// Array list of items
items: items.map((String data) {
return DropdownMenuItem(
value: data,
child: SizedBox(
height: 15,
width: 120.0, // for example
child: Text(data,
style: const TextStyle(
fontSize: 13.0,
fontWeight: FontWeight.w700),
textAlign: TextAlign.center),
),
);
}).toList(),
// After selecting the desired option,it will
// change button value to selected value
onChanged: (String? newValue) {
setState(
() {
dropdownValueMembers = newValue!;
},
);
},
),
),
),
],
),
Row(
children: [
Padding(
padding: const EdgeInsets.only(left: 20),
child: Text('Which child'),
),
Padding(
padding: const EdgeInsets.only(left: 100, right: 0, top: 20),
child: Container(
height: 30,
decoration: BoxDecoration(
boxShadow: const <BoxShadow>[
//apply shadow on Dropdown button
BoxShadow(
color: Color.fromRGBO(
0, 0, 0, 0.37), //shadow for button
blurRadius: 5) //blur radius of shadow
],
color: Colors.white,
borderRadius: BorderRadius.circular(15),
),
child: DropdownButton(
underline: Container(),
borderRadius: BorderRadius.circular(20),
// Initial Value
value: dropdownValueNumber,
// Down Arrow Icon
icon: const Icon(Icons.keyboard_arrow_down),
// Array list of items
items: number.map((String number) {
return DropdownMenuItem(
value: number,
child: SizedBox(
height: 17,
width: 120.0, // for example
child: Text(number,
style: const TextStyle(
fontSize: 13.0,
fontWeight: FontWeight.w700),
textAlign: TextAlign.center),
),
);
}).toList(),
// After selecting the desired option,it will
// change button value to selected value
onChanged: (String? newNumber) {
setState(
() {
dropdownValueNumber = newNumber!;
},
);
},
),
),
),
],
),
const SizedBox(
height: 60,
),
Padding(
padding: const EdgeInsets.only(left: 15),
child: Row(
children: <Widget>[
const Icon(
Icons.brightness_1,
color: Colors.black,
size: 10,
),
const Padding(
padding: EdgeInsets.only(left: 15.0),
child: Text("birthday",
style: TextStyle(
fontSize: 16.0,
)),
),
Padding(
padding: const EdgeInsets.only(left: 25.0),
child: SizedBox(
width: 110.0,
height: 25.0,
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
child: Center(
child: Text(
selectedDate == null
? (dropdownValueBirthday ?? birthday.first)
: '${selectedDate?.year}/${selectedDate?.month}/${selectedDate?.day} ',
style: const TextStyle(
fontSize: 16, fontWeight: FontWeight.w500),
),
),
),
),
),
Padding(
padding: const EdgeInsets.only(left: 15.0),
child: SizedBox(
width: 88.0,
height: 25.0,
child: MaterialButton(
onPressed: showDatePicker,
shape: const StadiumBorder(),
color: Colors.blue,
child: const Text(
'select',
style: TextStyle(color: Colors.white, fontSize: 12),
),
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(left: 15.0),
child: Row(
children: <Widget>[
const Icon(
Icons.brightness_1,
color: Colors.black,
size: 10,
),
const Padding(
padding: EdgeInsets.only(left: 15.0),
child: Text(
"Are you agree",
style:
TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
),
),
const Padding(
padding: EdgeInsets.only(left: 30),
child: Text(
'yes',
style:
TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
),
),
Checkbox(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
side: MaterialStateBorderSide.resolveWith(
(states) =>
BorderSide(width: 3.0, color: Colors.blueAccent),
),
value: isChecked,
onChanged: (bool? value) {
setState(() {
isChecked = value!;
});
},
),
],
),
),
Padding(
padding: const EdgeInsets.only(bottom: 0.0, top: 150),
child: SizedBox(
width: 160.0,
height: 35.0,
child: ElevatedButton(
style: ButtonStyle(
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
side: const BorderSide(
color: Colors.blueAccent,
),
),
),
),
onPressed: () {
//do null check 1st
_saveData(dropdownValueMembers!);
_saveDataNumbers(dropdownValueNumber!);
_saveDataBirthday(dropdownValueBirthday!);
_saveDataAgree(isChecked!);
},
child: const Text('next')),
),
),
],
),
),
);
}
}
How to solve and how to add sharedPreference to this datepicker and to checkbox
Lot's of ways to go about it. Simplist way in your case, get rid of all the setStates in all your methods except the last one. You're layering all those setStates and they're calling while other things are still awaiting.
I suggest awaiting each method before calling any setState. You can't await in the initState, but in the first method, call the each of the subsequent ones with awaits from there. So just call checkValueMembers(); (or create a new one getAllValues or whatever).
Within getAllValues, await all the other methods.
Then you can be sure that everything is done, and finally, call setState this way:
WidgetsBinding.instance.addPostFrameCallback((_) {
setState((){});
});
It ensures you don't call setState until the entire widget tree is done.
Entire thing could look like this: remember to get rid of all the other setStates
Future checkValueMembers() async {
await _getData();
await _getDataNumber();
await _getDataBirthday();
await _getDataAgree();
WidgetsBinding.instance.addPostFrameCallback((_) {
setState((){});
});
}
To keep things short:
I have multiple products, where you can increment and decrement their value(qnty) inside the cart and after Submitting, a receipt is generated based on the cart Items.
So the Problem is whenever I try to slide the submit, the qnty of the first product I added to cart is assigned to every product, Like
• Apple: 1
• Mango: 2
• Orange: 6
Above is how it should be like
• Apple: 6
• Mango: 6
• Orange: 6
This is the result I am getting, Note: The Result is from new to old
Secondary issue is that whenever I try to write any value inside the textfield and click submit, the value still doesn't get updated!
The Code consists of 2 files:
Parent File
import 'package:ambica_medico/component/result/productcart.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_email_sender/flutter_email_sender.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:whatsapp_unilink/whatsapp_unilink.dart';
import '../../component/buttons/c_button.dart';
import '../../constant.dart';
final FirebaseAuth auth = FirebaseAuth.instance;
Stream<QuerySnapshot> getData() => FirebaseFirestore.instance
.collection('Users')
.doc(auth.currentUser?.uid)
.collection('Carts')
.snapshots();
class Cart extends StatefulWidget {
const Cart({Key? key}) : super(key: key);
#override
State<Cart> createState() => _CartState();
}
class _CartState extends State<Cart> {
String _text = '';
callback(newAbc) {
pk = newAbc;
} //Step 5: Callback ready to be passed to the the Procart.
String? product;
String qnty = '';
String? mail;
String? name;
String? address;
String? dln;
String? gst;
late final _getData = getData();
DateTime now = DateTime.now();
Map<String, String> pk = {};
#override
Widget build(BuildContext context) {
return StreamBuilder<dynamic>(
stream: _getData,
builder: (context, snapshot) {
final tilesList = <Widget>[];
if (snapshot.hasData) {
snapshot.data.docs.forEach((value) {
qnty = value.data()['SIB'].toString();
pk = {value.id: qnty}; //Step4: A map which holds every product id and qnty
final productTile = Procart(
pname: value.data()['Product'],
subtitle: value.data()['MRP'],
keyo: value.id,
controller: qnty, sib: value.data()['OSIB'], tis: value.data()['TIS'], callback: callback, //Callback passed!
);
if (_text.isEmpty) {
tilesList.add(productTile);
} else {
if (value
.data()['Product']
.toUpperCase()
.contains(_text.toUpperCase())) {
tilesList.add(productTile);
}
}
// print(pk.values); //Returns 5,1
});
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
leading: Padding(
padding: const EdgeInsets.only(left: 20.0, top: 10),
child: IconButton(
icon: const Icon(
Icons.arrow_back_ios_new_rounded,
color: Colors.black,
size: 20,
),
onPressed: () {
Navigator.pop(context);
},
),
),
backgroundColor: const Color(0xFFf5f3f7),
elevation: 0,
),
body: GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: Container(
decoration: kImageBackground.copyWith(),
height: MediaQuery.of(context).size.height,
child: Stack(children: [
Column(
children: [
SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(
left: 24.0, right: 24.0, top: 40),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text(
'The Cart',
style: TextStyle(
fontSize: 40,
fontFamily: 'ProductSans',
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
Padding(
padding:
const EdgeInsets.only(top: 50, bottom: 50),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Color(0x261B1B1A),
blurRadius: 50.0,
spreadRadius: 0,
offset: Offset(0.0, 30.0),
),
],
),
height: 70,
child: Center(
child: TextField(
onChanged: (value) {
setState(() {
_text = value;
});
},
keyboardType: TextInputType.text,
decoration: kDecorS.copyWith(
hintText: 'Search Products',
),
style: const TextStyle(
fontFamily: 'ProductSans',
fontSize: 18,
fontWeight: FontWeight.w400,
color: Color(0xff0f1511),
),
),
),
),
),
],
),
),
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.55,
child: ListView(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
children: tilesList,
),
),
],
),
Positioned(
bottom: 0,
child: SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
width: MediaQuery.of(context).size.width,
decoration: const BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(42.0),
topRight: Radius.circular(42.0),
),
color: Colors.white,
),
child: Padding(
padding: const EdgeInsets.only(top: 20),
child: Column(
children: [
const Padding(
padding:
EdgeInsets.only(bottom: 10.0),
child: Center(
child: Text(
'Check and then click below to',
style: TextStyle(
fontSize: 14,
fontFamily: 'ProductSans',
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
),
),
Cbutton(
text: 'Send Order',
onPressed: () async {
String message = "";
DateTime date = DateTime(
now.year, now.month, now.day);
await FirebaseFirestore.instance
.collection('Users')
.doc(auth.currentUser?.uid)
.get()
.then((value) => {
name = value.data()!['name'],
address =
value.data()!['address'],
dln = value.data()!['dln'],
gst = value.data()!['gst'],
});
await snapshot.data.docs
.forEach((value) async {
product = value.data()['Product'];
message += '- $product = ${pk.values} \n';
});
final Email email = Email(
body:
"From:- \n\nName: $name\n\nAddress: $address\n\nDrug License No:- $dln\n\nGST No:- $gst\n\nDate:- $date \n\nDear sir,\nPlease dispatch my following order earliest possible through\n $message \n\nThanks & Regards,\n$name",
subject: 'Order Detail',
recipients: ['calagency03#gmail.com'],
isHTML: false,
);
final link = WhatsAppUnilink(
phoneNumber: '+91 2313210000',
text:
"From:- \n\nName: $name\n\nAddress: $address\n\nDrug License No:- $dln\n\nGST No:- $gst\n\nDate:- $date \n\nDear sir,\nPlease dispatch my following order earliest possible through\n $message \n\nThanks & Regards,\n$name",
);
await FlutterEmailSender.send(email);
final url = Uri.parse('$link');
await launchUrl(url, mode: LaunchMode.externalApplication,);
},
icon: const Icon(
Icons.send_rounded,
color: Colors.black,
size: 20,
),
color: const Color(0xff0f1511),
),
],
),
),
),
),
),
)
]),
),
),
),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
});
}
}
The main logic of printing the receipt for a product is:
await snapshot.data.docs
.forEach((value) async {
product = value.data()['Product'];
message += '- $product = ${pk.values} \n';
});
Child File
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
class Procart extends StatefulWidget {
final String pname;
final String subtitle;
final String keyo; // Step1: Product id
final String sib;
final String tis;
final String controller; // Step2: Initial Value/ Qnty
final Function(Map) callback; // Step3: Callback to parents widget in which it passes updated qnty
const Procart(
{Key? key,
required this.pname,
required this.subtitle,
required this.keyo, required this.controller, required this.sib, required this.tis, required this.callback})
: super(key: key);
#override
State<Procart> createState() => _ProcartState();
}
class _ProcartState extends State<Procart> {
final FirebaseAuth auth = FirebaseAuth.instance;
late TextEditingController controller = TextEditingController(text: widget.controller);
Map<String, String> lk = {};
sub() {
setState(() {
controller.text =
(int.parse(controller.text) - 1).toString();
});
}
add() {
setState(() {
controller.text =
(int.parse(controller.text) + 1).toString();
});
}
// #override
// void didUpdateWidget(covariant Procart oldWidget) {
// // TODO: implement didUpdateWidget
// super.didUpdateWidget(oldWidget);
//
//
// }
#override
Widget build(BuildContext context) {
lk = { widget.keyo : controller.text }; // This map is used to store updated value
widget.callback(lk); // send updated value back to parent class but the value still remains 2,2,2 instead of 1,7,2
print(lk.values);
return GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Slidable(
key: Key(widget.keyo),
endActionPane: ActionPane(motion: const ScrollMotion(), children: [
SlidableAction(
// An action can be bigger than the others.
onPressed: (value) {
FirebaseFirestore.instance
.collection('Users')
.doc(auth.currentUser?.uid)
.collection('Carts')
.doc(widget.keyo)
.delete();
},
backgroundColor: const Color(0xFFD16464),
foregroundColor: Colors.white,
icon: Icons.clear_rounded,
),
]),
child: Padding(
padding: const EdgeInsets.only(left: 28.0, right: 28.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10)
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.4,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.pname,
style: const TextStyle(
fontFamily: 'Satoshi',
fontSize: 16,
fontWeight: FontWeight.bold,
color: Color(0xff0f1511),
),
),
Text(
'${widget.subtitle} | ${widget.sib} x ${widget.tis}',
style: const TextStyle(
fontFamily: 'Satoshi',
fontSize: 12,
fontWeight: FontWeight.normal,
color: Color(0xff0f1511),
),
),
],
),
),
Row(
children: [
CircleAvatar(
radius: 16,
backgroundColor: const Color(0xff1b1b1b),
child: IconButton(
iconSize: 13,
icon: const Icon(
Icons.remove,
color: Colors.white,
),
onPressed: () {
if (int.parse(controller.text) >
int.parse(widget.sib)) {
sub();
}
},
),
),
SizedBox(
width: 80,
child: TextFormField(
textAlign: TextAlign.center,
decoration: const InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.only(left: 6, right: 6),
),
controller: controller,
onEditingComplete: () {
controller;
},
keyboardType: TextInputType.number,
style: const TextStyle(
fontFamily: 'Satoshi',
fontSize: 16.0,
fontWeight: FontWeight.bold,
color: Color(0xff0f1511),
),
),
),
CircleAvatar(
radius: 16,
backgroundColor: const Color(0x33bababa),
child: IconButton(
iconSize: 13,
icon: const Icon(
Icons.add,
color: Color(0xff1b1b1b),
),
onPressed: () {
add();
},
),
),
],
),
]),
),
),
))),
);
}
}
For more info I have attached Screenshots below:
A Huge Thank you to anyone who helps me in solving this!
Well, I solved this issue by following the steps below:
I have 2 widgets ProfitDisplay() and BetListDisplay(), I want to be able to share data from a firestore query without calling the same query twice. For ProfitDisplay() I'll need at least 1 more stream. My current code queries the db twice once for each widget which is not very efficient. I tried wrapping ListView() with StreamProvider.value() but then I got an error saying it could not find the Provider.
The query is based on dates selected in the first widget in the ListView()
class DailyPage extends StatefulWidget {
const DailyPage({Key? key}) : super(key: key);
#override
_DailyPageState createState() => _DailyPageState();
}
class _DailyPageState extends State<DailyPage> {
final FirebaseAuth auth = FirebaseAuth.instance;
final DateTime now = DateTime.now();
final days = getWeekDayList;
int _currentWeekDayNameAndNum = getCurrentWeekDayInt();
final db = FirestoreService();
#override
Widget build(BuildContext context) {
int selectedDay = int.parse(days[_currentWeekDayNameAndNum]['day']);
final User? user = auth.currentUser;
DateTime startDate = DateTime(now.year, now.month, selectedDay, 00, 00);
DateTime endDate = DateTime(now.year, now.month, selectedDay, 23, 59);
return Scaffold(
backgroundColor: white.withOpacity(1),
body: ListView(
children: [
Column(
children: [
Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(color: white, boxShadow: [
BoxShadow(
color: grey.withOpacity(0.5),
spreadRadius: 4,
blurRadius: 5,
// changes position of shadow
),
]),
child: Padding(
padding: const EdgeInsets.only(
top: 10, right: 10, left: 10, bottom: 20),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text(
"Daily Transactions",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: black),
),
],
),
const SizedBox(
height: 25,
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: List.generate(days.length, (index) {
return GestureDetector(
onTap: () {
setState(() {
_currentWeekDayNameAndNum = index;
});
},
child: SizedBox(
width:
(MediaQuery.of(context).size.width - 40) /
7,
child: Column(
children: [
Text(
days[index]['label'],
style: const TextStyle(fontSize: 10),
),
const SizedBox(
height: 10,
),
Container(
width: 30,
height: 30,
decoration: BoxDecoration(
color: _currentWeekDayNameAndNum ==
index
? primary
: Colors.transparent,
shape: BoxShape.circle,
border: Border.all(
color:
_currentWeekDayNameAndNum ==
index
? primary
: black
.withOpacity(0.1))),
child: Center(
child: Text(
days[index]['day'],
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w600,
color:
_currentWeekDayNameAndNum ==
index
? white
: black),
),
),
)
],
),
),
);
}))
],
),
),
),
],
),
StreamProvider<List<BetData>>.value(
value: FirestoreService()
.streamBetDataBetweenDates(user!, startDate, endDate),
initialData: [],
child: const ProfitDisplay(),
),
const SizedBox(
height: 10,
),
StreamProvider<List<BetData>>.value(
value: FirestoreService()
.streamBetDataBetweenDates(user, startDate, endDate),
initialData: [],
child: const BetListDisplay(),
)
],
));
}
}
class _ProfitDisplayState extends State<ProfitDisplay> {
double _dailyTotal = 0;
#override
Widget build(BuildContext context) {
List betList = Provider.of<List<BetData>>(context);
double _total = 0;
for (var bet in betList) {
_total += bet.value;
}
_dailyTotal = _total;
return Container(
margin: const EdgeInsets.fromLTRB(8, 8, 8, 0),
decoration: BoxDecoration(color: white, boxShadow: [
BoxShadow(
color: grey.withOpacity(0.5),
spreadRadius: 4,
blurRadius: 5,
// changes position of shadow
),
]),
child: Container(
alignment: Alignment.center,
margin: const EdgeInsets.all(8),
child: _dailyTotal > 0
? Text(
'£ ${_dailyTotal.toString()}',
style: const TextStyle(
color: Colors.green,
fontSize: 25,
fontWeight: FontWeight.bold),
)
: Text(
'£ ${_dailyTotal.toString()}',
style: const TextStyle(
color: Colors.red,
fontSize: 25,
fontWeight: FontWeight.bold),
),
));
}
}
Not sure if it's relevant but here's FirestoreService()
class FirestoreService {
final FirebaseFirestore _db = FirebaseFirestore.instance;
/// List of bets between startDate and endData
Stream<List<BetData>> streamBetDataBetweenDates(
User user, DateTime startDate, DateTime endDate) {
var ref = _db
.collection('users/${user.uid}/bets')
.where('d', isGreaterThanOrEqualTo: startDate)
.where('d', isLessThanOrEqualTo: endDate)
.orderBy('d', descending: true);
print('this got called at ${DateTime.now()}');
return ref.snapshots().map(
(list) => list.docs.map((doc) => BetData.fromFirestore(doc)).toList());
}
}
Here I have a form like this. i want to change the value of the blue button week below when i swipe left or right of Calendar Week. What should i do guys ?. It can only changed when I clicked on the number
Here is the code I'm using:
import 'package:flutter/material.dart';
import 'package:myhumgupdate/App/Config/palette.dart';
import 'package:myhumgupdate/Widgets/dialog_loading.dart';
import 'package:myhumgupdate/giangvien/Screens/XemTKB/TKBTheoTuan/tkbtuan_viewmodel.dart';
import 'package:myhumgupdate/Widgets/calender_week.dart';
import 'package:myhumgupdate/giangvien/models/meeting.dart';
import 'package:myhumgupdate/giangvien/models/meetingdata_source.dart';
import 'package:stacked/stacked.dart';
import 'package:syncfusion_flutter_calendar/calendar.dart';
class TKBTuan extends StatefulWidget {
#override
_TKBTuanState createState() => _TKBTuanState();
}
final String _customTimeLabelText = 'Tiết';
class _TKBTuanState extends State<TKBTuan> {
#override
Widget build(BuildContext context) {
return ViewModelBuilder<TKBTuanViewModel>.reactive(
onModelReady: (model) => Future.delayed(Duration.zero,
() => DialogLoading.show(context, model.getTkbTuan(model.timeNow))),
builder: (context, TKBTuanViewModel model, child) => Column(
children: [
Row(
children: [
Expanded(
child: Container(
margin: EdgeInsets.only(
top: 18,
),
child: CalendarWeek(
calendarController: model.calendarController,
press: (DateTime date, _, __) {
model.getTkbTuan(date);
},
),
),
),
Container(
width: 40,
height: 56,
margin: EdgeInsets.only(right: 3),
padding: EdgeInsets.symmetric(horizontal: 4, vertical: 5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Palette.kPrimaryColor,
),
child: Center(
child: Text(
"Week ${model.week}",
style: TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
),
],
),
Expanded(
child: SfCalendar(
view: CalendarView.week,
firstDayOfWeek: 1,
maxDate: DateTime(DateTime.now().year, DateTime.now().month,
DateTime.now().day, 00, 45, 0),
minDate: DateTime(DateTime.now().year, DateTime.now().month,
DateTime.now().day, 00, 45, 0),
headerHeight: 0,
viewHeaderHeight: 0,
dataSource: MeetingDataSource(model.getDataSource),
appointmentTimeTextFormat: 'hh:mm:ss a',
appointmentBuilder: appointmentBuilder,
initialDisplayDate: DateTime(DateTime.now().year,
DateTime.now().month, DateTime.now().day, 00, 45, 0),
monthViewSettings: MonthViewSettings(showAgenda: true),
timeSlotViewSettings: TimeSlotViewSettings(
startHour: 0,
endHour: 16,
timeFormat: _customTimeLabelText + " H",
timeIntervalHeight: 70,
timeTextStyle: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
)),
// selectionDecoration: BoxDecoration(
// color: Colors.transparent,
// border: Border.all(color: Colors.red, width: 1),
// borderRadius: const BorderRadius.all(Radius.circular(4)),
// shape: BoxShape.rectangle,
// ),
),
),
],
),
viewModelBuilder: () => TKBTuanViewModel());
}
}
Widget appointmentBuilder(BuildContext context,
CalendarAppointmentDetails calendarAppointmentDetails) {
final Meeting appointment = calendarAppointmentDetails.appointments.first;
return Container(
width: calendarAppointmentDetails.bounds.width,
height: calendarAppointmentDetails.bounds.height,
// color: appointment.background,
decoration: BoxDecoration(
color: appointment.background,
border: Border.all(
color: Colors.grey,
width: 0.5,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(2.0, 0, 0, 5.0),
child: Text(
appointment.eventName,
// textAlign: TextAlign.center,
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(2.0, 0, 0, 0),
child: Text(
"Phòng: ${appointment.subText}",
style: TextStyle(fontSize: 10, fontStyle: FontStyle.italic),
),
)
],
),
);
}
And if there is no way to change the value like that, what should I do and how can I change that?
In the Flutter Event Calendar, you can programmatically select the date using selectedDate property of the CalendarController.
Inside the state, initialize the calendar controller.
final CalendarController _calendarController= CalendarController();
Using onViewChanged callback of the Flutter event calendar, you can set the first date of visible dates as selected date.
child: SfCalendar(
view: CalendarView.month,
controller: _calendarController,
onViewChanged: viewChanged,
),
void viewChanged(ViewChangedDetails viewChangedDetails) {
SchedulerBinding.instance!.addPostFrameCallback((Duration duration) {
_calendarController.selectedDate = viewChangedDetails.visibleDates[0];
});
}
Wrap your Widget in GestureDetector and use onPanUpdate like this:
GestureDetector(onPanUpdate: (details) {
if (details.delta.dx > 0) {
// swiping in right direction
// update week number
}
});