Change data while using Calendar Week in Flutter - flutter

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

Related

Why doesn't my state change in my stateful widget even when I pass data through constructors flutter?

Hello guys i have two stateful widget InactiveCustomersListView and MessageCustomerHeader
InactiveCustomersListView has a List of tiles, and these tiles have checkboxes
class InactiveCustomersListView extends StatefulWidget {
final bool checkAll;
const InactiveCustomersListView({
Key key,
this.checkAll,
}) : super(key: key);
#override
State<InactiveCustomersListView> createState() =>
_InactiveCustomersListViewState();
}
class _InactiveCustomersListViewState extends State<InactiveCustomersListView> {
bool checkAll;
List<CheckBoxModel> listOfCustomers = [];
#override
void initState() {
listOfCustomers.addAll({
CheckBoxModel(selected: false),
});
super.initState();
}
#override
Widget build(BuildContext context) {
final controller = Get.put(CustomersController());
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: listOfCustomers.length,
itemBuilder: (context, index) {
return Obx(() {
return Container(
color: Color(0xffFFFFFF),
child: ListTile(
contentPadding: controller.isCheboxVisible.isTrue
? EdgeInsets.only(left: 0, right: 22, top: 10, bottom: 10)
: EdgeInsets.only(left: 22, right: 22, top: 10, bottom: 10),
horizontalTitleGap: 5,
leading: controller.isCheboxVisible.isTrue
? Visibility(
visible: controller.isCheboxVisible.value,
child: Transform.scale(
scale: 1.3,
child: Checkbox(
side: MaterialStateBorderSide.resolveWith(
(Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return const BorderSide(
width: 2, color: Color(0xff34495E));
}
return const BorderSide(
width: 1, color: Color(0xffB0BEC1));
},
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
activeColor: Color(0xff34495E),
//materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
//visualDensity: VisualDensity(horizontal: -4, vertical: -4),
value: listOfCustomers[index].selected,
onChanged: (value) {
setState(() {
listOfCustomers[index].selected = value;
final check = listOfCustomers
.every((element) => element.selected);
checkAll = check;
});
},
),
),
)
: null,
title: Row(
children: [
SizedBox(
width: 60,
height: 60,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(80)),
child: CachedNetworkImage(
height: 100,
width: double.infinity,
fit: BoxFit.cover,
imageUrl:
Get.find<AuthService>().user.value.avatar.thumb,
placeholder: (context, url) => Image.asset(
'assets/img/loading.gif',
fit: BoxFit.cover,
width: double.infinity,
height: 80,
),
errorWidget: (context, url, error) =>
Icon(Icons.error_outline),
),
),
),
SizedBox(
width: 10,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'John Cletus',
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Color(0xff151515)),
),
Container(
decoration: BoxDecoration(
color: Color(0xffECF0F1),
borderRadius: BorderRadius.circular(20),
),
child: Padding(
padding: const EdgeInsets.only(
left: 10.0,
right: 10.0,
top: 5.0,
bottom: 5.0),
child: Text(
'Inactive',
style: GoogleFonts.poppins(
fontSize: 10,
fontWeight: FontWeight.w400,
color: Color(0xff7F8D90)),
),
),
),
],
),
SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Text(
'2',
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Color(0xff151515)),
),
SizedBox(
width: 5,
),
Text(
'jobs',
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w400,
color: Color(0xff151515)),
),
],
),
Text(
'Last job 5 days ago',
style: GoogleFonts.poppins(
fontSize: 9,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w400,
color: Color(0xff151515)),
),
],
),
],
),
),
],
),
),
);
});
});
}
}
class CheckBoxModel {
bool selected;
CheckBoxModel({this.selected});
}
MessageCustomerHeader widget class has a checkbox that controls the Check boxes in the InactiveCustomersListView widget class:
class MessageCustomerHeader extends StatefulWidget {
final List<CheckBoxModel> listOfCustomers;
const MessageCustomerHeader({
Key key,
this.listOfCustomers,
}) : super(key: key);
#override
State<MessageCustomerHeader> createState() => _MessageCustomerHeaderState();
}
class _MessageCustomerHeaderState extends State<MessageCustomerHeader> {
bool checkAll = false;
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Select customers you woult like to message',
style: GoogleFonts.poppins(
color: Color(0xff596780).withOpacity(0.8),
fontSize: 14,
fontWeight: FontWeight.w500),
),
SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Transform.scale(
scale: 1.3,
child: Checkbox(
side: MaterialStateBorderSide.resolveWith(
(Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return const BorderSide(
width: 2, color: Color(0xff34495E));
}
return const BorderSide(
width: 1, color: Color(0xffB0BEC1));
},
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
activeColor: Color(0xff34495E),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
visualDensity: VisualDensity(horizontal: -4, vertical: -4),
value: checkAll,
onChanged: (value) {
setState(() {
checkAll = value;
widget.listOfCustomers.forEach((element) {
element.selected = value;
});
});
},
),
),
SizedBox(
width: 10,
),
Text(
'Select all',
style: GoogleFonts.poppins(
color: Colors.black87,
fontSize: 12,
fontWeight: FontWeight.w400),
),
],
),
],
),
),
);
}
}
I tried using constructor to pass "listOfCustomers" from InactiveCustomersListView widget to MessageCustomerHeader widget
And also passing "checkAll" from MessageCustomerHeader to InactiveCustomersListView widget by also using constructors.
The problem is having is that when i click on the checkbox in MessageCustomerHeader widget to check all the check boxes in InactiveCustomersListView widget, the state don't seem to change and it doesn't even after setting all the logic. What am i doing wrong guys and how do i resolve this issue :(
This is the error i get when i tap the checkbox on the MessageCustomerHeader checkbox.
"The method 'forEach' was called on null.
Receiver: null
Tried calling: forEach(Closure: (CheckBoxModel) => Null)"
Thank you.
If you have the proper lints enabled you would have seen this warning: DON'T put any logic in createState().
From the associated description:
Implementations of createState() should return a new instance of a State object and do nothing more. Since state access is preferred via the widget field, passing data to State objects using custom constructor parameters should also be avoided and so further, the State constructor is required to be passed no arguments.
(emphasis added)
You are passing arguments to your State constructors. Instead, use widget.checkAll and widget.listOfCustomers to access widget properties from the state objects.
Also:
It would be better to specify a type for checkAll. In your code you just have final checkAll;.
It is difficult to read the screen shot of the error message. It would be better to include the error message as text in the question, along with an indication in your code of the line to which the error message is referring.

How to hide can't selecting date in datePicker on flutter?

My UI
In this datePicker only can select maximum of 2 years and 29days from today (6/10/2020), the minimum day is 1 year from today(5/11//2021), So I want to hide other dates ( can't select years) How to do that?
Ex: From Today maximum year is 2020 so want to hide 2019,2018,2017......
And minimum year is 2021 so want hide 2022
code
import 'package:age_calculator/age_calculator.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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();
}
//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 != selectedDate) {
setState(() {
selectedDate = value;
'Birthday'
'${selectedDate?.year}/${selectedDate?.month}/${selectedDate?.day} ';
calAge();
});
}
},
maximumDate: maxdate,
minimumDate: mindate,
),
);
});
}
String age = "";
DateDuration? duration;
getAge(DateTime fromDate) =>
DateTime.now().difference(fromDate).inDays ~/ 365;
void calAge() {
DateTime? birthday = selectedDate;
setState(() {
duration = AgeCalculator.age(birthday!);
});
}
#override
Widget build(BuildContext context) {
print(duration);
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
? 'Birthday'
: '${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: () {},
child: const Text('next')),
),
),
],
),
),
);
}
}
Simply use maximumYear and minimumYear Properties that's already avaliable in CupertinoDatePicker class.
// This code will hide all the years except 2021 and 2020 only
CupertinoDatePicker(
maximumYear:2021,
minimumYear : 2020,
initialDateTime: date,
)
Hope this answer help you and thanks.

Flutter, single streamprovider shared between multiple widgets

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

flutter Problem same quantity show on products

when I am increasing my quantity of one product then all product's quantity is increasing, so how to solve it.
This is my product page:
import 'dart:convert';
import 'package:carousel_pro/carousel_pro.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:hospital/Authentication/LoginLogoutScreenPage/login.dart';
import 'package:hospital/CartPage/Cart_Api/cart_api.dart';
import 'package:hospital/CartPage/pages/cartPage.dart';
import 'package:hospital/Drawer/dropdown_menu.dart';
import 'package:hospital/ProductDetailsPage/product_detailPage.dart';
import 'package:hospital/ProductDetailsPage/related_product_page.dart';
import 'package:hospital/SecondSection/Medicine/medicine_page.dart';
import 'package:hospital/constant.dart';
import 'package:hospital/customApiVariable.dart';
import 'package:http/http.dart' as http;
import 'package:line_icons/line_icons.dart';
import 'package:provider/provider.dart';
class DetailPage extends StatefulWidget {
final plistId;
const DetailPage({Key key, this.plistId}) : super(key: key);
#override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
final GlobalKey<FormState> _formKey = GlobalKey();
int quantity = 1;
var response;
var detailPageApi;
#override
void initState() {
super.initState();
fetchData(widget.plistId);
}
fetchData(var consultWithDoctor) async {
var api = Uri.parse(
'$ecommerceBaseUrl/productListApi.php?a2rTokenKey=$a2rTokenKey&plistId=${widget.plistId}');
response = await http.get(
api,
);
print("detailPageApi " + api.toString());
print("detailPageBody " + response.body);
detailPageApi = jsonDecode(response.body);
print("detailPagelist " + detailPageApi.toString());
setState(() {});
}
Future _submit() async {
var errorMessage = 'Authentication Failed';
if (successfully_add_cart_status.toString() == 'false') {
errorMessage = 'Please try again later';
print(errorMessage);
_showerrorDialog(errorMessage);
} else {
errorMessage = 'Product Succesfully Added to Cart';
print(errorMessage);
_showerrorDialog(errorMessage);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: kGreen,
title: Text(
"Details",
style: TextStyle(fontStyle: FontStyle.italic),
),
actions: [
IconButton(
icon: Icon(Icons.shopping_cart),
// onPressed: () => print("open cart"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Cartpage()),
);
},
),
DropDownMenu(),
],
),
body: Container(
child: response != null
? ListView.builder(
itemCount: detailPageApi.length.clamp(0, 1),
scrollDirection: Axis.vertical,
physics: ScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, index) {
var details = detailPageApi[index];
if (details['num'] == 0) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.white,
),
);
}
return Column(
children: <Widget>[
Hero(
tag: "1",
child: SizedBox(
height: 300.0,
width: 300.0,
child: Carousel(
boxFit: BoxFit.cover,
autoplay: false,
animationCurve: Curves.fastOutSlowIn,
animationDuration: Duration(milliseconds: 800),
dotSize: 6.0,
dotIncreasedColor: Colors.black,
dotBgColor: Colors.transparent,
// dotPosition: DotPosition.topRight,
dotVerticalPadding: 10.0,
showIndicator: true,
indicatorBgPadding: 7.0,
images: [
NetworkImage(details['pImgImg']),
],
),
),
),
SizedBox(
height: 50,
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Name :",
style: TextStyle(
fontSize: 18,
height: 1.5,
fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Flexible(
child: Text(
// widget.details,
details['productName'],
style: TextStyle(
fontSize: 17,
height: 1.5,
fontWeight: FontWeight.w500),
),
),
],
),
),
SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Details :",
style: TextStyle(
fontSize: 18,
height: 1.5,
fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Flexible(
child: Text(
// widget.details,
details['productDescription'],
style: TextStyle(
fontSize: 17,
height: 1.5,
fontWeight: FontWeight.w500),
),
),
],
),
),
SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: Row(
children: <Widget>[
Text(
"Price :",
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Row(
children: <Widget>[
Text(
// "Rs " + widget.pPromotionPrice,
"Rs 55.0",
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Text(
// "Rs " + widget.pPrice,
"Rs 100",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
// color: warning,
decoration: TextDecoration.lineThrough),
)
],
)
],
),
),
SizedBox(
height: 25,
),
Padding(
padding: const EdgeInsets.only(right: 20, left: 20),
child: Row(
children: <Widget>[
Text(
"Qty :",
style: TextStyle(
fontSize: 17, fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Row(
children: <Widget>[
InkWell(
onTap: () {
if (quantity > 1) {
setState(() {
quantity = --quantity;
});
}
// minus here
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(
// border: Border.all(color: primary),
shape: BoxShape.circle),
child: Icon(
LineIcons.minus,
size: 15,
),
),
),
SizedBox(
width: 15,
),
Text(
quantity.toString(),
style: TextStyle(fontSize: 16),
),
SizedBox(
width: 15,
),
InkWell(
onTap: () {
setState(() {
quantity = ++quantity;
});
// minus here
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(
// border: Border.all(color: primary),
shape: BoxShape.circle),
child: Icon(
LineIcons.plus,
size: 15,
),
),
),
],
)
],
),
),
SizedBox(
height: 50,
),
InkWell(
onTap: () async {
if (var_uid.toString() != null.toString()) {
_submit();
var qty = quantity.toString();
var plistId = widget.plistId;
print('pplistid' + plistId);
var uid = var_uid.toString();
var sid = var_sid.toString();
print('uuid' + uid);
print('ssid' + sid);
var response =
await add_to_cart_fn(qty, plistId, uid, sid);
print("rsp: " + response['msg']);
} else {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => LoginPage()));
}
},
// },
child: Padding(
padding: EdgeInsets.only(left: 20, right: 20),
child: Container(
height: 45,
width: double.infinity,
decoration: BoxDecoration(
color: kGreen,
borderRadius: BorderRadius.circular(30)),
child: Center(
child: Text(
"ADD TO CART",
style: TextStyle(
color: kWhite,
fontSize: 20,
),
),
),
),
),
),
SizedBox(height: 20.0),
RelatedProductPage(plistId: widget.plistId)
],
);
})
: Center(
child: CircularProgressIndicator(
backgroundColor: Colors.white,
),
),
),
);
}
void _showerrorDialog(String message) {
Fluttertoast.showToast(
msg: message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
backgroundColor: Colors.grey[350],
textColor: Colors.black,
fontSize: 16.0);
}
}
You are using the same quantity variable against each item. Changing the value on one of those will cause all items to update. What you need to do is to keep a Map of quantity selected against product id. That way whenever you increase or decrease the quantity, you update the quantity against that specific product id and the rest will remain unchanged.
EDIT: Here is how this will work
//Create a new map to save the product id and product selected quantity
var productQuantity = new Map<int, int>()
//When setting the values of the product, set the quantity from the map
Padding(
padding: const EdgeInsets.only(right: 20, left: 20),
child: Row(
children: <Widget>[
Text(
"Qty :",
style: TextStyle(
fontSize: 17, fontWeight: FontWeight.w500),
),
SizedBox(width: 20,),
Row(
children: <Widget>[
InkWell(
onTap: () {
if (quantity > 1) {
setState(() {
//Changed here
productQuantity['$productId'] -= 1;
});
}
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(shape: BoxShape.circle),
child: Icon(
LineIcons.minus,
size: 15,
),
),
),
SizedBox(width: 15,),
Text(
//Changed here
productQuantity['$productId'].toString(),
style: TextStyle(fontSize: 16),
),
SizedBox(width: 15,),
InkWell(
onTap: () {
setState(() {
//Changed here
productQuantity['$productId'] += 1;
});
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(
shape: BoxShape.circle),
),
child: Icon(
LineIcons.plus,
size: 15,
),
),
),
],
)
],
),
)
you set the common quantity in all products so change it and set it inside the class.
Please Check the example
import 'package:flutter/material.dart';
class QuantityUpdatePage extends StatefulWidget {
#override
_QuantityUpdatePageState createState() => _QuantityUpdatePageState();
}
class _QuantityUpdatePageState extends State<QuantityUpdatePage> {
List<Product> productArray = [];
#override
void initState() {
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
productArray.clear();
productArray.add(Product(1, "Product 1", 1));
productArray.add(Product(2, "Product 2", 1));
productArray.add(Product(3, "Product 3", 1));
productArray.add(Product(4, "Product 4", 1));
productArray.add(Product(5, "Product 5", 1));
setState(() {});
});
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("QUANTITY UPDATE")),
body: ListView.builder(
shrinkWrap: true,
itemCount: productArray.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(right: 20, left: 20),
child: ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: [
SizedBox(
height: 20,
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(productArray[index].productName),
SizedBox(
width: 40,
),
Row(
children: <Widget>[
Text(
"Qty :",
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Row(
children: <Widget>[
InkWell(
onTap: () {
if (productArray[index].quantity > 1) {
setState(() {
productArray[index].quantity = --productArray[index].quantity;
});
}
// minus here
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(
// border: Border.all(color: primary),
shape: BoxShape.circle),
child: Icon(
Icons.minimize,
size: 15,
),
),
),
SizedBox(
width: 15,
),
Text(
productArray[index].quantity.toString(),
style: TextStyle(fontSize: 16),
),
SizedBox(
width: 15,
),
InkWell(
onTap: () {
setState(() {
productArray[index].quantity = ++productArray[index].quantity;
});
// minus here
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(
// border: Border.all(color: primary),
shape: BoxShape.circle),
child: Icon(
Icons.add,
size: 15,
),
),
),
],
)
],
),
],
),
SizedBox(
height: 20,
),
],
),
);
}));
}
}
class Product {
String productName;
int quantity;
int id;
Product(this.id, this.productName, this.quantity);
}
#Deepak if you don't understand Maps use list instead, with a value being updated for each index. Initialize a list of int types with some large values like 1000000, and update the value for each index. use ListView builder to fetch the data from the API for each index.
List<int> quantity = List.empty(growable: true);
OR
List<int> quantity = List.filled(10000, []);
For updating quantity:-
quantity[index] += 1;
For Grid view thing, refer this example from CodeGrepper:-
GridView.count(
// Create a grid with 2 columns. If you change the scrollDirection to
// horizontal, this produces 2 rows.
crossAxisCount: 2,
// Generate 100 widgets that display their index in the List.
children: List.generate(100, (index) {
return Center(
child: Text(
'Item $index',
style: Theme.of(context).textTheme.headline5,
),
);
}),
);

trying to add to bag and to update prices and cups

I am trying to do this test TODOs: but i have been have issuses pls help: i am trying to Uncomment the _confirmOrderModalBottomSheet() method to show summary of order, Uncomment the setState() function to clear the price and cups, and Change the 'price' to 0 when this button is clicked Increment the _cupsCounter when 'Add to Bag' button is clicked, and to Call setState((){}) method to update both price and cups counter when 'Add to Bag' button is clicked
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Coffee Test',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.white,
),
home: MyHomePage(title: 'Coffee Test'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _selectedPosition = -1;
String _coffeePrice ="0";
int _cupsCounter =0;
int price = 0;
String _currency ="₦";
static const String coffeeCup ="images/coffee_cup_size.png";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
title: FlatButton(
onPressed: (){
//TODO: Uncomment the _confirmOrderModalBottomSheet() method to show summary of order
//_confirmOrderModalBottomSheet(totalPrice: "$_currency$price", numOfCups: "x $_cupsCounter");
},
child: Text("Buy Now",style: TextStyle(color: Colors.black87),),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(18.0), side: BorderSide(color: Colors.blue))
),
actions: [
InkWell(
onTap: () {
//TODO: Uncomment the setState() function to clear the price and cups
//TODO: Change the 'price' to 0 when this button is clicked
setState(() {
this.price = -1;
this._cupsCounter = 0;
});
Icon(Icons.clear);
}),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Container(
height: double.maxFinite,
alignment: Alignment.center,
child: Text("$_cupsCounter Cups = $_currency$price.00", style: TextStyle(fontSize: 18),),
),
)
],
),
body: Padding(padding: EdgeInsets.all(20), child: _mainBody(),) // This trailing comma makes auto-formatting nicer for build methods.
);
}
Widget _mainBody(){
return SingleChildScrollView(
child: Container(
height: double.maxFinite,
width: double.maxFinite,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 0,
child: Stack(
children: [
Container(
width: double.maxFinite,
height: 250,
margin: EdgeInsets.only(left: 50, right: 50, bottom: 50, top: 60),
decoration: BoxDecoration(borderRadius:
BorderRadius.all(Radius.circular(180)),
color: Color.fromRGBO(239, 235, 233, 100)),
),
Container(
alignment: Alignment.center,
width: double.maxFinite,
height: 350,
child: Image.asset("images/cup_of_coffee.png", height: 300,),
)
],
)),
Padding(padding: EdgeInsets.all(10),),
Expanded(flex: 0,child: Text("Caffè Americano",
style: TextStyle(fontWeight: FontWeight.bold,
fontSize: 30),)),
Padding(padding: EdgeInsets.all(6),),
Expanded(flex: 0, child: Text("Select the cup size you want and we will deliver it to you in less than 48hours",
style: TextStyle(fontWeight: FontWeight.bold,
fontSize: 14, color: Colors.black45,),
textAlign: TextAlign.start,),
),
Container(
margin: EdgeInsets.only(top: 30, left: 20),
height: 55,
width: double.maxFinite,
alignment: Alignment.center,
child:Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
RichText(text: TextSpan(
text: _currency,
style: TextStyle(fontWeight: FontWeight.bold,
fontSize: 25, color: Colors.black87),
children: [
TextSpan(text: _coffeePrice, style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold))
]
),),
Padding(
padding: EdgeInsets.only(right: 15),
),
ListView.builder(itemBuilder: (context, index){
return InkWell(
child: _coffeeSizeButton(_selectedPosition == index,
index ==0? "S" : index ==1? "M": "L"),
onTap: (){
setState(() {
this._coffeePrice= index ==0? "300" : index ==1? "600": "900";
_selectedPosition = index;
});
},
);
}, scrollDirection: Axis.horizontal,
itemCount: 3, shrinkWrap: true,),
],),
),
Container(
margin: EdgeInsets.only(top: 30),
padding: EdgeInsets.all(10),
width: double.maxFinite,
height: 70,
child: FlatButton(onPressed: (){
//TODO: Currently _cupsCounter only show 1 when this button is clicked.
// TODO: Increment the _cupsCounter when 'Add to Bag' button is clicked'
//TODO: Call setState((){}) method to update both price and cups counter when 'Add to Bag' button is clicked
this._cupsCounter = 1;
this.price += int.parse(_coffeePrice);
}, child: Center(child: Text("Add to Bag",
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white),)
,),
color: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50)
),
),
)
],
),
),
);
}
Widget _coffeeSizeButton(bool isSelected, String coffeeSize){
return Stack(
children: [
Container(alignment: Alignment.center, width: 55,
child: Text(coffeeSize, style: TextStyle(fontSize: 10, fontWeight: FontWeight.bold,
color: isSelected? Colors.blue: Colors.black45),),),
new Container(
margin: EdgeInsets.only(right: 10),
child: Image.asset(coffeeCup, width:50, color: isSelected ? Colors.blue: Colors.black45,),
decoration: BoxDecoration(border: Border(top: BorderSide(color: isSelected? Colors.blue: Colors.black45,
width: isSelected? 2: 1), left: BorderSide(color: isSelected? Colors.blue: Colors.black45,
width: isSelected? 2: 1), bottom: BorderSide(color: isSelected? Colors.blue: Colors.black45,
width: isSelected? 2: 1), right: BorderSide(color: isSelected ?Colors.blue: Colors.black45 ,
width: isSelected? 2: 1)), borderRadius: BorderRadius.all(Radius.circular(5))),
)
],
);
}
void _confirmOrderModalBottomSheet({String totalPrice, String numOfCups}){
showModalBottomSheet(
context: context,
builder: (builder){
return new Container(
height: 150.0,
color: Colors.transparent, //could change this to Color(0xFF737373),
//so you don't have to change MaterialApp canvasColor
child: new Container(
padding: EdgeInsets.all(10),
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(10.0),
topRight: const Radius.circular(10.0))),
child: Column(
children: [
Container(
child: Text("Confirm Order",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),),
alignment: Alignment.center, height: 30, decoration: BoxDecoration(
), ),
_getEstimate(totalPrice, numOfCups)
],
)),
);
}
);
}
Widget _getEstimate(String totalPrice, String numOfCups){
return Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Image.asset("images/cup_of_coffee.png", height: 70, width: 50,),
Padding(padding: EdgeInsets.all(10)),
Text(numOfCups, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),),
Padding(padding: EdgeInsets.all(10)),
Text(totalPrice, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),)
],
);
}
}
You're setting 1 to your _cupsCounter instead of adding one to it.
When updating your values, putting the operation i.e _cupsCounter += 1; in setState will update the state of your widget which makes values change in your widgets.
setState((){
_cupsCounter += 1; // make it +=1 instead of =1.
price += int.parse(_coffeePrice);
});
Also you can use setState by putting it after your operation which will update the state of your widget after the operation is done.
_cupsCounter += 1; // make it +=1 instead of =1.
price += int.parse(_coffeePrice);
setState((){});
Full code should look like this.
Container(
margin: EdgeInsets.only(top: 30),
padding: EdgeInsets.all(10),
width: double.maxFinite,
height: 70,
child: FlatButton(onPressed: (){
// Currently _cupsCounter only show 1 when this button is clicked.
// Increment the _cupsCounter when 'Add to Bag' button is clicked'
// Call setState((){}) method to update both price and cups counter when 'Add to Bag' button is clicked
setState((){
_cupsCounter += 1; // make it +=1 instead of =1.
price += int.parse(_coffeePrice);
}); // call setState like this
}, child: Center(child: Text("Add to Bag",
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white),)
,),
color: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50)
),
),
)