I created a simple calendar widget. I want to create a personal calendar for each user. For this purpose, I am using a ListView.builder.
Please find my code below
#override
Widget build(BuildContext context) {
return new SizedBox(
height: 1000,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: bookingList.length,
itemBuilder: (context, index) {
return Column(
children: [
BookingCalendar(
bookingService: bookingCalendarModel,
convertStreamResultToDateTimeRanges:
convertStreamResultMock,
getBookingStream: getBookingStreamMock,
uploadBooking: uploadBookingMock,
pauseSlots: generatePauseSlots(),
hideBreakTime: false,
loadingWidget: const Text('Fetching data...'),
uploadingWidget: const CircularProgressIndicator(),
locale: 'en_US',
startingDayOfWeek: CalendarDays.monday,
wholeDayIsBookedWidget:
const Text('Fully booked! Choose another day'),
disabledDates: [DateTime(2023, 1, 20)],
disabledDays: [6, 7])
],
);
}));
}
Everytime when i add the custom widget(BookingCalendar) inside the ListView i am getting a lot of errors:
No Material widget found.
Could you please tell my where is my mistake?
full code here:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:test_honours/model/doctors.dart';
import '../core/booking_calendar.dart';
import '../model/booking_service.dart';
import '../model/enums.dart';
void main() {
initializeDateFormatting()
.then((_) => runApp(const BookingCalendarDemoApp()));
}
class BookingCalendarDemoApp extends StatefulWidget {
const BookingCalendarDemoApp({Key? key}) : super(key: key);
#override
State<BookingCalendarDemoApp> createState() => _BookingCalendarDemoAppState();
}
class _BookingCalendarDemoAppState extends State<BookingCalendarDemoApp> {
final now = DateTime.now();
late BookingModel bookingCalendarModel;
List<BookingModel> bookingList = [];
#override
void initState() {
super.initState();
for (var i = 0; i < doctorsList.length; i++) {
Doctor doctor = doctorsList[i];
bookingList.add(bookingCalendarModel = new BookingModel(
apptName: 'Mock Service',
apptDuration: doctor.duration,
bookingEnd: doctor.endHour,
bookingStart: doctor.startHour));
}
}
Stream<dynamic>? getBookingStreamMock(
{required DateTime end, required DateTime start}) {
return Stream.value([]);
}
Future<dynamic> uploadBookingMock({required BookingModel newBooking}) async {
await Future.delayed(const Duration(seconds: 1));
converted.add(DateTimeRange(
start: newBooking.bookingStart, end: newBooking.bookingEnd));
print('${newBooking.toJson()} has been uploaded');
}
List<DateTimeRange> converted = [];
List<DateTimeRange> convertStreamResultMock({required dynamic streamResult}) {
///here you can parse the streamresult and convert to [List<DateTimeRange>]
///take care this is only mock, so if you add today as disabledDays it will still be visible on the first load
///disabledDays will properly work with real data
DateTime first = now;
DateTime tomorrow = now.add(Duration(days: 1));
DateTime second = now.add(const Duration(minutes: 55));
DateTime third = now.subtract(const Duration(minutes: 240));
DateTime fourth = now.subtract(const Duration(minutes: 500));
converted.add(
DateTimeRange(start: first, end: now.add(const Duration(minutes: 30))));
converted.add(DateTimeRange(
start: second, end: second.add(const Duration(minutes: 23))));
converted.add(DateTimeRange(
start: third, end: third.add(const Duration(minutes: 15))));
converted.add(DateTimeRange(
start: fourth, end: fourth.add(const Duration(minutes: 50))));
//book whole day example
converted.add(DateTimeRange(
start: DateTime(tomorrow.year, tomorrow.month, tomorrow.day, 5, 0),
end: DateTime(tomorrow.year, tomorrow.month, tomorrow.day, 23, 0)));
return converted;
}
List<DateTimeRange> generatePauseSlots() {
return [
DateTimeRange(
start: DateTime(now.year, now.month, now.day, 12, 0),
end: DateTime(now.year, now.month, now.day, 14, 0))
];
}
#override
Widget build(BuildContext context) {
return new SizedBox(
height: 1000,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: bookingList.length,
itemBuilder: (context, index) {
return Column(
children: [
BookingCalendar(
bookingService: bookingCalendarModel,
convertStreamResultToDateTimeRanges:
convertStreamResultMock,
getBookingStream: getBookingStreamMock,
uploadBooking: uploadBookingMock,
pauseSlots: generatePauseSlots(),
hideBreakTime: false,
loadingWidget: const Text('Fetching data...'),
uploadingWidget: const CircularProgressIndicator(),
locale: 'en_US',
startingDayOfWeek: CalendarDays.monday,
wholeDayIsBookedWidget:
const Text('Fully booked! Choose another day'),
disabledDates: [DateTime(2023, 1, 20)],
disabledDays: [6, 7])
],
);
}));
}
}
You are missing MaterialApp on main method
void main() {
initializeDateFormatting().then(
(_) => runApp(
MaterialApp(
home: const BookingCalendarDemoApp(),
),
),
);
}
This is because you can't Define Root Widget:
MaterialApp
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:test_honours/model/doctors.dart';
import '../core/booking_calendar.dart';
import '../model/booking_service.dart';
import '../model/enums.dart';
void main() {
initializeDateFormatting()
.then((_) => runApp(const MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home:BookingCalendarDemoApp(),
);
}
}
class BookingCalendarDemoApp extends StatefulWidget {
const BookingCalendarDemoApp({Key? key}) : super(key: key);
#override
State<BookingCalendarDemoApp> createState() => _BookingCalendarDemoAppState();
}
class _BookingCalendarDemoAppState extends State<BookingCalendarDemoApp> {
final now = DateTime.now();
late BookingModel bookingCalendarModel;
List<BookingModel> bookingList = [];
#override
void initState() {
super.initState();
for (var i = 0; i < doctorsList.length; i++) {
Doctor doctor = doctorsList[i];
bookingList.add(bookingCalendarModel = new BookingModel(
apptName: 'Mock Service',
apptDuration: doctor.duration,
bookingEnd: doctor.endHour,
bookingStart: doctor.startHour));
}
}
Stream<dynamic>? getBookingStreamMock(
{required DateTime end, required DateTime start}) {
return Stream.value([]);
}
Future<dynamic> uploadBookingMock({required BookingModel newBooking}) async {
await Future.delayed(const Duration(seconds: 1));
converted.add(DateTimeRange(
start: newBooking.bookingStart, end: newBooking.bookingEnd));
print('${newBooking.toJson()} has been uploaded');
}
List<DateTimeRange> converted = [];
List<DateTimeRange> convertStreamResultMock({required dynamic streamResult}) {
///here you can parse the streamresult and convert to [List<DateTimeRange>]
///take care this is only mock, so if you add today as disabledDays it will still be visible on the first load
///disabledDays will properly work with real data
DateTime first = now;
DateTime tomorrow = now.add(Duration(days: 1));
DateTime second = now.add(const Duration(minutes: 55));
DateTime third = now.subtract(const Duration(minutes: 240));
DateTime fourth = now.subtract(const Duration(minutes: 500));
converted.add(
DateTimeRange(start: first, end: now.add(const Duration(minutes: 30))));
converted.add(DateTimeRange(
start: second, end: second.add(const Duration(minutes: 23))));
converted.add(DateTimeRange(
start: third, end: third.add(const Duration(minutes: 15))));
converted.add(DateTimeRange(
start: fourth, end: fourth.add(const Duration(minutes: 50))));
//book whole day example
converted.add(DateTimeRange(
start: DateTime(tomorrow.year, tomorrow.month, tomorrow.day, 5, 0),
end: DateTime(tomorrow.year, tomorrow.month, tomorrow.day, 23, 0)));
return converted;
}
List<DateTimeRange> generatePauseSlots() {
return [
DateTimeRange(
start: DateTime(now.year, now.month, now.day, 12, 0),
end: DateTime(now.year, now.month, now.day, 14, 0))
];
}
#override
Widget build(BuildContext context) {
return new SizedBox(
height: 1000,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: bookingList.length,
itemBuilder: (context, index) {
return Column(
children: [
BookingCalendar(
bookingService: bookingCalendarModel,
convertStreamResultToDateTimeRanges:
convertStreamResultMock,
getBookingStream: getBookingStreamMock,
uploadBooking: uploadBookingMock,
pauseSlots: generatePauseSlots(),
hideBreakTime: false,
loadingWidget: const Text('Fetching data...'),
uploadingWidget: const CircularProgressIndicator(),
locale: 'en_US',
startingDayOfWeek: CalendarDays.monday,
wholeDayIsBookedWidget:
const Text('Fully booked! Choose another day'),
disabledDates: [DateTime(2023, 1, 20)],
disabledDays: [6, 7])
],
);
}));
}
}
Related
I have the following code with a DateTimeRange and I would like to allow the user to select a range without exceed 15 days. For example a range before today will be 02/02 to 02/16 or lower or after today 02/14 to 03/01 or lower. How can I do that if it's possible ?
class DateRangeView extends StatefulWidget {
late bool isClearClicked;
DateRangeView({Key? key, required this.isClearClicked}) : super(key: key);
#override
DateRangeView createState() => DateRangeViewState();
}
class DateRangeViewState extends State<DateRangeView> {
DateTimeRange? dateRange;
DateTimeRange? initialDateRange;
DateTimeRange? newDateRange;
String getFrom() {
if (dateRange == null) {
return DateTime.now().toRangeDate();
} else {
return dateRange!.start.toRangeDate();
}
}
String getUntil() {
if (dateRange == null) {
return DateTime.now().toRangeDate();
} else {
return dateRange!.end.toRangeDate();
}
}
#override
Widget build(BuildContext context) {
return HeaderWidget(
title: Translation.current.period.toUpperCase(),
child: Row(
children: [
Expanded(
child: ButtonWidget(
text: widget.isClearClicked
? DateTime.now().toRangeDate()
: getFrom(),
onClicked: () => pickDateRange(context),
),
),
Text(Translation.current.untilDateKeyword.toUpperCase(),
style:
TextStyle(fontSize: ThemeSize.text(xl), color: ThemeColor.gray500),
),
Expanded(
child: ButtonWidget(
text: widget.isClearClicked
? DateTime.now().toRangeDate()
: getUntil(),
onClicked: () => pickDateRange(context),
),
),
Icon( Icons.calendar_month_rounded, color: ThemeColor.gray600,),
],
),
);
}
Future pickDateRange(BuildContext context) async {
initialDateRange = DateTimeRange(
start: DateTime.now(),
end: DateTime.now(),
);
newDateRange = await showDateRangePicker(
initialEntryMode: DatePickerEntryMode.calendarOnly,
context: context,
firstDate: DateTime(2022),
lastDate: DateTime(2030),
initialDateRange: dateRange ?? initialDateRange,
builder: (context, Widget? child) => Theme(
data:ThemeData.light().copyWith(
//Header background color
primaryColor: ThemeColor.primaryVariant,
scaffoldBackgroundColor: Colors.grey[50],
dividerColor: Colors.grey,
textTheme: TextTheme(
bodyText2:
TextStyle(color: ThemeColor.gray700, fontSize: ThemeSize.text(xxl)),
),
colorScheme: ColorScheme.fromSwatch().copyWith(
primary: ThemeColor.primaryVariant,
onSurface: Colors.black,
),
),
child: child!,
),
);
if (newDateRange == null) return;
setDateRange();
}
setDateRange() {
setState(() {
dateRange = newDateRange;
widget.isClearClicked = false;
});
Future.delayed(
const Duration(milliseconds: 100), () {
dateRange = initialDateRange;
},
);
}
}
You can use syncfusion_flutter_datepicker library. It has a selectionChanged callback that you can manipulate to limit selectable dates on the go. This is my answer to a similar question
class Home extends StatefulWidget {
const Home({super.key});
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
final DateTime _minDate = DateTime.now();
DateTime _maxDate = DateTime.now().add(const Duration(days: 365));
final Duration _duration = const Duration(days: 14);
DateTime _start = DateTime.now();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SfDateRangePicker(
minDate: _minDate,
maxDate: _maxDate,
selectionMode: DateRangePickerSelectionMode.range,
onSelectionChanged: (DateRangePickerSelectionChangedArgs args) {
if (args.value is PickerDateRange) {
_start = (args.value as PickerDateRange).startDate!;
setState(() {
// limit the maxDate to 14 days from selected date
_maxDate = _start.add(_duration);
});
}
},
)),
);
}
}
You can change this two params to :
firstDate: DateTime.now(),
lastDate: DateTime.now().add(Duration(days: 15)),
This is the firebase database structure that I am using:
import 'package:awesome_dropdown/awesome_dropdown.dart';
import 'package:carousel_slider/carousel_controller.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:hexated/Refactored/widgets/headings.dart';
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
import '../Refactored/sections/bottomNavigation.dart';
import '../Refactored/sections/todaysMealContainer.dart';
import '../Refactored/widgets/mealDayList.dart';
class messDiary extends StatefulWidget {
messDiary({Key? key}) : super(key: key) {}
// late String whatIsToday = DateFormat('EEEE').format(DateTime.now());
#override
State<messDiary> createState() => _messDiaryState();
}
class _messDiaryState extends State<messDiary> {
int activeIndex = 0;
final carouselController = CarouselController();
String valueChoose = 'Select a day';
var itemName;
final CollectionReference _collectData =
FirebaseFirestore.instance.collection('messdiary');
late Stream<QuerySnapshot> _streamCollect;
#override
void initState() {
super.initState();
_streamCollect = _collectData.snapshots();
}
#override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
return Scaffold(
backgroundColor: const Color(0xFF000000),
appBar: AppBar(
backgroundColor: const Color(0xFF000000),
elevation: 0,
),
bottomNavigationBar: const bottomNavigation(),
body: ListView(
children: [
Column(
children: [
headings(headingText: "Today's meals"),
const SizedBox(
height: 15,
),
StreamBuilder<QuerySnapshot>(
stream: _streamCollect,
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
List<DocumentSnapshot> snaps = snapshot.data!.docs;
return CarouselSlider(
options: CarouselOptions(
height: height * 0.38,
aspectRatio: 2.0,
autoPlayCurve: Curves.easeInOutQuart,
pauseAutoPlayOnTouch: true,
enlargeCenterPage: true,
enableInfiniteScroll: false,
initialPage: 2,
autoPlay: true,
onPageChanged: (index, reason) {
setState(() {
activeIndex = index;
});
},
),
items: snaps.map((e) {
return Builder(builder: (BuildContext context) {
return todaysMeal(
itemName: e['title'],
itemImage: e['image'],
time: e['time'],
dayTime: e['daytime']);
});
}).toList(),
);
}),
const SizedBox(
height: 15,
),
AnimatedSmoothIndicator(
onDotClicked: animateToSlide,
effect: const ExpandingDotsEffect(
dotWidth: 14,
dotHeight: 14,
activeDotColor: Color(0xFF6A7086),
dotColor: Color(0xFF2B2E3F)),
activeIndex: activeIndex,
count: 4,
),
],
),
);
}
}
When i try to run the code this error message appears
======== Exception caught by widgets library ======================================================= The following StateError was thrown building Builder(dirty):
Bad state: field does not exist within the DocumentSnapshotPlatform
If it is not the way to access the data then how??
i have tried to the end and tired please help me to fix this issue!!
The field names are 'sunday', 'monday', and so on. Each of these fields has an array of [todaysMeal] jsons, in a manner of speaking.
What you are trying to access are the fields inside each array element.
So what's happening is: you are looking for json keys 'title', 'image', 'daytime', and 'time', but the document snapshot has these keys: 'sunday', 'monday', etc.
I don't think I worded this answer very well, but I hope this was enough to clear up your confusion.
I am replying to your comments here. Here are the code changes that you can try.
// First of all change the don't use the CollectionReference for 'messdiary'.
// final CollectionReference _collectData = FirebaseFirestore.instance.collection('messdiary');
// Use the DocumentReference for 'days'.
final DocumentReference _daysData =
FirebaseFirestore.instance.collection('messdiary').doc('days');
Then:-
// Change the following statement.
// List<DocumentSnapshot> snaps = snapshot.data!.docs;
// to this:
final daysObj = snapshot.data()!;
final sundayMeals = daysObj["sunday"]
.map((e)=>todaysMeal(itemName: e['title'], itemImage: e['image'], time: e['time'], dayTime: e['daytime']))
.toList();
final mondayMeals = ...
...
final saturdayMeals = ...
final mealsData = [...sundayMeals, ...mondayMeals, ....... , ...saturdayMeals];
// Now use mealsData for your carousel.
This code might not work entirely as you expected. You have to do any further debugging.
And if you need further help, I might have to charge you 😜.
class messDiary extends StatefulWidget { messDiary({Key? key}) : super(key: key) {}
// late String whatIsToday = DateFormat('EEEE').format(DateTime.now());
#override State<messDiary> createState() => _messDiaryState(); }
class _messDiaryState extends State<messDiary> { int activeIndex = 0; final carouselController = CarouselController(); String valueChoose = 'Select a day'; var itemName;
final DocumentReference _collectData =
FirebaseFirestore.instance.collection('messdiary').doc('days');
late Stream<DocumentSnapshot> _streamCollect;
#override void initState() {
super.initState();
_streamCollect = _collectData.snapshots(); }
#override Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
return Scaffold(
backgroundColor: const Color(0xFF000000),
appBar: AppBar(
backgroundColor: const Color(0xFF000000),
elevation: 0,
),
bottomNavigationBar: const bottomNavigation(),
body: ListView(
children: [
Column(
children: [
headings(headingText: "Today's meals"),
const SizedBox(
height: 15,
),
StreamBuilder<DocumentSnapshot>(
stream: _streamCollect,
builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
final snaps = snapshot.data!;
final sundayMeals = snaps["sunday"]
.map((e) => todaysMeal(
itemName: e['title'],
itemImage: e['image'],
time: e['time'],
dayTime: e['daytime']))
.toList();
final List<Widget> mealsData = [...sundayMeals];
return CarouselSlider(
options: CarouselOptions(
height: height * 0.38,
aspectRatio: 2.0,
autoPlayCurve: Curves.easeInOutQuart,
pauseAutoPlayTouch: true,
enlargeCenterPage: true,
enableInfiniteScroll: false,
initialPage: 2,
autoPlay: true,
onPageChanged: (index, reason) {
setState(() {
activeIndex = index;
});
},
),
items: mealsData,
);
}),
const SizedBox(
height: 15,
),
AnimatedSmoothIndicator(
onDotClicked: animateToSlide,
effect: const ExpandingDotsEffect(
dotWidth: 14,
dotHeight: 14,
activeDotColor: Color(0xFF6A7086),
dotColor: Color(0xFF2B2E3F)),
activeIndex: activeIndex,
count: 4,
),
const SizedBox(
height: 15,
),
const Divider(
color: Color(0xFF6A6C70),
indent: 20,
endIndent: 20,
),
],
),
],
),
); }
void animateToSlide(int index) => carouselController.animateToPage(index); }
This is my code:
class MobileHomePage extends StatefulWidget {
const MobileHomePage({Key? key}) : super(key: key);
#override
State<MobileHomePage> createState() => _MobileHomePageState();
}
class _MobileHomePageState extends State<MobileHomePage> {
#override
void setState(fn) {
if (mounted) {
super.setState(fn);
}
}
int? second;
#override
void initState() {
second = int.parse(DateFormat.s().format(DateTime.now()));
Timer.periodic(const Duration(seconds: 1), (timer) => getCurrentTime());
super.initState();
}
void getCurrentTime() {
setState(() {
second = int.parse(DateFormat.s().format(DateTime.now()));
});
}
User user = FirebaseAuth.instance.currentUser!;
final Stream<QuerySnapshot> _mainSubjectStream = FirebaseFirestore.instance
.collection('systems')
.orderBy('system_name', descending: false)
.snapshots();
#override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
final GlobalKey<ScaffoldState> _key = GlobalKey();
return Scaffold(
key: _key,
body: SafeArea(
bottom: false,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
flex: 1,
child: Container(
color: Colors.transparent,
child: StreamBuilder<QuerySnapshot>(
stream: _mainSubjectStream,
builder: (context, mainSubjectSnapshot) {
if (mainSubjectSnapshot.hasError) {
return const Center(child: Text('Error));
}
if (mainSubjectSnapshot.connectionState ==
ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
var length = mainSubjectSnapshot.data!.docs.length;
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: length,
itemBuilder: (context, i) {
var output = mainSubjectSnapshot.data!.docs[i];
return Text(output['name']);
});
},
),
)),
const Spacer(flex: 3),
Expanded(
flex: 5,
child: DatePicker(
DateTime.now(),
initialSelectedDate: _date,
daysCount: 8,
locale: 'pt',
selectionColor: const Color.fromRGBO(67, 97, 238, 1),
selectedTextColor: Colors.white,
onDateChange: (date){
setState(() {
_date = date;
});
},
),
),
Expanded(
flex: 1,
child: Text(second.toString()
),
],
),
));
}
}
When I try to display the clock (as in second.toString()), the StreamBuilder is also updated, resulting in a new progress indicator each second. What is breaking my head is that I just copied the same strutted that I used in other code – which works fine. Did I do something wrong? Why is it influencing the other stream?
EDIT
Have just found out that the error is related to the key in the scaffold. When I deleted it, it worked fine. The thing is that I need I as I have a custom button to open the drawer. 1st question is how does it influences it. 2nd question is how to solve it?
I'm having a problem using Firestore and Syncfusion Flutter Charts in Flutter.
I'm querying from firestore some documents, awaiting the result so the function must be a Future, but I need it to be a List, not a Future<List>. This is my code:
#override
Widget build(BuildContext context) {
return Expanded(
child: SfCartesianChart(
primaryXAxis: CategoryAxis(
majorGridLines: const MajorGridLines(width: 0),
axisLine: const AxisLine(width: 0),
),
primaryYAxis: NumericAxis(
majorGridLines: const MajorGridLines(width: 0),
axisLine: const AxisLine(width: 0),
),
plotAreaBorderWidth: 0,
series: getData(),
),
);
}
String getcurrentMonth() {
DateTime date = DateTime.now();
return DateFormat.MMMM().format(date).substring(0, 3);
}
List<String> getOtherMonths() {
List<String> otherMonths = [];
DateTime date = DateTime.now();
for (var i = 1; i < 5; i++) {
DateTime prev = DateTime(date.year, date.month - i, date.day);
otherMonths.add(DateFormat.MMMM().format(prev).substring(0, 3));
}
return otherMonths;
}
Future<List<double>> getTotalByMonth() async {
List<double> totals = [];
DateTime date = DateTime.now();
for (var i = 0; i < 5; i++) {
var lastDay = DateTime(date.year, date.month - i + 1, 0);
DateTime startOfMonth = DateTime(date.year, date.month - i, 1);
DateTime endOfMonth =
DateTime(date.year, date.month - i, lastDay.day, 23, 59, 59, 999);
Timestamp startTimestamp = Timestamp.fromDate(startOfMonth);
Timestamp endTimestamp = Timestamp.fromDate(endOfMonth);
await FirebaseFirestore.instance
.collection('users/$uid/receipts')
.where('date', isGreaterThanOrEqualTo: startTimestamp)
.where('date', isLessThanOrEqualTo: endTimestamp)
.get()
.then((doc) {
double monthTot = 0;
doc.docs.forEach((element) {
monthTot += element.data()['total'];
});
totals.add(monthTot);
});
}
return totals;
}
Future<List<ChartSeries<BarChartModel, String>>> getData() async {
String currentMonth = getcurrentMonth();
List<String> months = getOtherMonths();
months.insert(0, currentMonth);
months = months.reversed.toList();
List<double> totals = await getTotalByMonth();
List<BarChartModel> data = [];
for (var i = 0; i < 5; i++) {
var obj = BarChartModel(months[i], totals[i],
i % 2 == 0 ? const Color(0xff003f9a) : const Color(0xff468fea));
data.add(obj);
}
return <ChartSeries<BarChartModel, String>>[
ColumnSeries<BarChartModel, String>(
dataSource: data,
xValueMapper: (BarChartModel data, _) => data.month,
yValueMapper: (BarChartModel data, _) => data.total,
pointColorMapper: (BarChartModel data, _) => data.month == currentMonth
? const Color(0xffeaa146)
: data.barColor,
animationDuration: 1000,
borderRadius: const BorderRadius.only(
topRight: Radius.circular(5),
topLeft: Radius.circular(5),
),
),
];
}
And this is the model:
class BarChartModel {
final String month;
final double total;
final Color barColor;
BarChartModel(this.month, this.total, this.barColor);
}
This is the error I get when I reload the app:
type 'Future<List<ChartSeries<BarChartModel, String>>>' is not a subtype of type 'List<ChartSeries<dynamic, dynamic>>'
What's the best way to get rid of the Future type in this case?
A FutureBuilder widget will help here.
Check out https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html for how to use a FutureBuilder.
Basic idea: FutureBuilder will load the data that you want to show. During loading you will show a progressIndicator. When loading is finished the data can be showed, which will not be a future anymore, but the actual data.
We have analyzed your query from our side, and we suggest you use the FutureBuilder because it builds itself based on the latest snapshot of interaction with a Future. We have provided the code snippet below for your reference you can modify this based on your requirement.
Code snippet:
late Future<List<ChartSeries<BarChartModel, String>>> chartData;
#override
void initState() {
chartData = getData();
super.initState();
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: chartData,
builder: (context, snapshot) {
if (snapshot.hasData) {
return SfCartesianChart(
primaryXAxis: CategoryAxis(
majorGridLines: const MajorGridLines(width: 0),
axisLine: const AxisLine(width: 0),
),
primaryYAxis: NumericAxis(
majorGridLines: const MajorGridLines(width: 0),
axisLine: const AxisLine(width: 0),
),
plotAreaBorderWidth: 0,
series: snapshot.data,
);
} else if (snapshot.hasError) {
return const Text('Something went wrong');
} else {
return const CircularProgressIndicator();
}
});
}
I'm trying to get value from mysql database into my flutter project(these using pagination). i'm add custom data and its work. but cant fetch my database value
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:http/http.dart'as http;
class AllQuestion extends StatefulWidget {
String fldPaperTypeID;
AllQuestion({this.fldPaperTypeID});
#override
_AllQuestionState createState() => _AllQuestionState();
}
List<Question> _question;
List<Question> populateData;
QuestionDataSource _questionDataSource = QuestionDataSource();
List<Question> paginatedDataSource = [];
class _AllQuestionState extends State<AllQuestion> {
bool showLoadingIndicator = true;
Future<List> GetAllQuestion() async{
final response = await http.post('http://eduapp.studysmile.lk/getquestion',body: {"fldPaperTypeID":widget.fldPaperTypeID});
return json.decode(response.body);
}
#override
void initState() {
// TODO: implement initState
super.initState();
_question = populateData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Question'),
),
body: LayoutBuilder(
builder: (context, constraints) {
return Row(children: [
Column(
children: [
SizedBox(
height: constraints.maxHeight - 60,
width: constraints.maxWidth,
child: buildStack(constraints)),
Container(
height: 60,
width: constraints.maxWidth,
child: SfDataPager(
rowsPerPage: 1,
direction: Axis.horizontal,
onPageNavigationStart: (int pageIndex) {
setState(() {
showLoadingIndicator = true;
});
},
delegate: _questionDataSource,
onPageNavigationEnd: (int pageIndex) {
setState(() {
showLoadingIndicator = false;
});
},
),
)
],
),
]);
},
),
);
}
Widget buildDataGrid(BoxConstraints constraint) {
return SfDataGrid(
source: _questionDataSource,
columnWidthMode: ColumnWidthMode.fill,
columns: <GridColumn>[
GridNumericColumn(mappingName: 'id', headerText: 'ID'),
GridTextColumn(mappingName: 'name', headerText: 'Name'),
GridNumericColumn(mappingName: 'salaryS', headerText: 'Salary'),
]);
}
Widget buildStack(BoxConstraints constraints) {
List<Widget> _getChildren() {
final List<Widget> stackChildren = [];
stackChildren.add(buildDataGrid(constraints));
if (showLoadingIndicator) {
stackChildren.add(Container(
color: Colors.black12,
width: constraints.maxWidth,
height: constraints.maxHeight,
child: Align(
alignment: Alignment.center,
child: CircularProgressIndicator(
strokeWidth: 3,
),
),
));
}
return stackChildren;
}
return Stack(
children: _getChildren(),
);
}
/* List<Question> populateData() {
return [
Question(10001, 'James', 20000),
Question(10002, 'Kathryn', 30000),
Question(10001, 'James', 20000),
Question(10002, 'Kathryn', 30000),
Question(10001, 'James', 20000),
Question(10002, 'Kathryn', 30000),
Question(10001, 'James', 20000),
Question(10002, 'Kathryn', 30000),
Question(10001, 'James', 20000),
Question(10002, 'Kathryn', 30000),
];
}*/
Future<List<Question>> populateData()async{
final response = await http.post('http://eduapp.studysmile.lk/getquestion',body:
{"fldPaperTypeID":widget.fldPaperTypeID});
List<Question> populateData = json.decode(response.body);
return populateData;
}
}
/*
class SendallQuestion extends StatelessWidget {
List list;
SendallQuestion({this.list});
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: list == null?0:list.length,
itemBuilder: (ctx,i){
return Container(
alignment: Alignment.center,
margin: EdgeInsets.all(20),
child: FlatButton(
child: Align(
alignment: Alignment(0.2, 0.6),
child: Text(list[i]['fldQuestion'], style: TextStyle(fontSize: 20.0),)
),
color: Color(0xff7c4dff),
textColor: Colors.white,
onPressed: (){
},
),
);
}
);
}
}*/
class Question{
final int fldQuestionID;
final int fldPaperTypeID;
final String fldQuestion;
Question(this.fldPaperTypeID,this.fldQuestion,this.fldQuestionID);
}
class QuestionDataSource extends DataGridSource<Question> {
#override
List<Question> get dataSource => paginatedDataSource;
#override
Object getValue(Question question, String columnName) {
switch (columnName) {
case 'id':
return question.fldPaperTypeID;
break;
case 'name':
return question.fldQuestionID;
break;
case 'salaryS':
return question.fldQuestion;
break;
default:
return ' ';
break;
}
}
#override
int get rowCount => _question.length;
#override
Future<bool> handlePageChange(int oldPageIndex, int newPageIndex,
int startRowIndex, int rowsPerPage) async {
int endIndex = startRowIndex + rowsPerPage;
if (endIndex > _question.length) {
endIndex = _question.length - 1;
}
await Future.delayed(Duration(milliseconds: 2000));
paginatedDataSource = List.from(
_question.getRange(startRowIndex, endIndex).toList(growable: false));
notifyListeners();
return true;
}
}
this was my error message **lib/allquestionview.dart:42:17: Error: A value of type 'Future<List>' can't be assigned to a variable of type 'List'.
'Future' is from 'dart:async'.
'List' is from 'dart:core'.
'Question' is from 'package:studysmile/allquestionview.dart' ('lib/allquestionview.dart').
_question = populateData();
^**
in your case i guess this will do the trick :
List _question = List();
Future GetAllQuestion() async{
final response = await http.post('http://eduapp.studysmile.lk/getquestion',body: {"fldPaperTypeID":widget.fldPaperTypeID});
var data = json.decode(response.body);
setState(() {
_question= data;
});
}
void initState() {
// TODO: implement initState
super.initState();
this.GetAllQuestion();
}
Try this code. It works.
import 'package:http/http.dart' as http;
import 'package:json_helpers/json_helpers.dart';
Future main() async {
final list = await populateData();
print(list[0].fldQuestion);
}
Future<List<Question>> populateData() async {
final typeID = '1';
final response = await http.post(
Uri.parse('http://eduapp.studysmile.lk/getquestion'),
body: {'fldPaperTypeID': typeID});
if (response.statusCode == 200) {
return response.body.jsonList((e) => Question.fromJson(e));
} else {
throw 'Bad response';
}
}
class Question {
final String fldQuestionID;
final String fldPaperTypeID;
final String fldQuestion;
Question({this.fldPaperTypeID, this.fldQuestion, this.fldQuestionID});
factory Question.fromJson(Map<String, dynamic> json) {
return Question(
fldPaperTypeID: json['fldPaperTypeID'] as String,
fldQuestion: json['fldQuestion'] as String,
fldQuestionID: json['fldQuestionID'] as String);
}
}
Output:
1. දත්ත සැකසීමට පෙර වලංගුතාවය පරික්ෂා කිරීමේදී අනුගමනය කළ යුතු වඩාත් නිවැරදි අනුපිළිවෙල වන්නේ