Confused about how to work around fl graphs and provider - flutter

I'm trying to create an app where there is a button, and when a user clicks on that button, that day's timestamp is recorded and is uploaded in firestore. And then I fetch the data from there and update a fl chart widget.
This is how I get the data from firebase, convert it to DateTime and send it to the graph building method.
Future<void> updateOfflineGraph(String uid) async {
//GraphData graphData = globalContext.watch<GraphData>();
GraphData graphData = GraphData();
List<dynamic> today = List<dynamic>();
List<DateTime> now = List<DateTime>();
try {
DocumentSnapshot _docSnapshot =
await _firestore.collection("graph").document(uid).get();
today.addAll(_docSnapshot.data()['dates']);
for (int i = 0; i < today.length; i++) {
now.add(DateTime.fromMicrosecondsSinceEpoch(
today[i].microsecondsSinceEpoch));
}
graphData.buildGraph(now);
} catch (e) {
print(e);
}
}
And this is how I process the data for the fl chart.
class GraphData with ChangeNotifier {
List<FlSpot> _data = List<FlSpot>();
List<int> _date = List<int>();
List<FlSpot> get data =>
List.unmodifiable(_data..sort((a, b) => a.x.compareTo(b.x)));
void addPoint(FlSpot spot) {
_data.add(spot);
notifyListeners();
}
void buildGraph(List<DateTime> dateTime) {
removeAllPoints();
int days = 0;
int month = dateTime[0].month;
for (int i = 0; i < dateTime.length; i++) {
if (dateTime[i].month == month) {
days++;
} else {
addMonth(days, month);
days = 0;
month = dateTime[i].month;
i--;
}
}
addMonth(days, month);
}
void addMonth(int days, int month) {
addPoint(FlSpot(month.toDouble(), days.toDouble()));
print(days);
print(month);
print(_data.length);
}
}
And then do this to update the graph.
LineChartBarData(
spots:
// [
// FlSpot(1, 3),
// FlSpot(2, 4),
// FlSpot(4, 5.5),
// FlSpot(5, 1),
// FlSpot(8, 4),
// FlSpot(12, 3),
// ],
context.watch<GraphData>().data.length > 0
? context.watch<GraphData>().data
: [FlSpot(0.0, 0.0)],
}
The problem that I'm facing is that when I do this whole thing, the points are stored in the _data list successfully, but when I try to call spots in LineChartBarData, it says that _data is null when it is called. I don't know why is this happening as the data was there in an iteration before.

Related

Flutter how to use multiple forloops

I am using this code but sometimes it runs the code in wrong order. Is it possible to wait for each for loop to finish before next one starts?
void changeWeek() {
for (int i = 0; i < newactivities.length; i++) {
int year = DateTime.now().year;
DateTime startDate = DateTime(year, 1, 1);
while (startDate.weekday != DateTime.monday) {
startDate = startDate.add(const Duration(days: 1));
}
for (String weekday in newactivities[i].daylistdone) {
int offset = (int.parse(weekday)) + (int.parse(currentweek) - 1) * 7;
DateTime donedate = startDate.add(Duration(days: offset));
oldDatesDone.add(Timestamp.fromDate(donedate));
}
for (String weekday in newactivities[i].daylist) {
int offset =
(int.parse(weekday) - 1) + (int.parse(currentweek) - 1) * 7;
DateTime notdonedate = startDate.add(Duration(days: offset));
oldDatesNotDone.add(Timestamp.fromDate(notdonedate));
}
for (var i in oldDatesDone) {
oldDatesNotDone.remove(i);
}
finaloldDatesDone = newactivities[i].weekdaysdone + oldDatesDone;
finaloldDatesNotDone = newactivities[i].weekdaysnotdone + oldDatesNotDone;
act.add({
'title': newactivities[i].title,
'days': newactivities[i].daylist,
'notificationidnumber': newactivities[i].notificationidnumber,
'daysdone': myData22,
'weekdaysdone': finaloldDatesDone,
'weekdaysnotdone': finaloldDatesNotDone,
'timelist': newactivities[i].timelist,
'time': newactivities[i].time
});
FirebaseFirestore.instance
.collection(widget.user.user.uid)
.doc(documentName)
.update({"activities": act});
}
}
Or can I do it in another way to solve the code?
Your Firebase update returns a Future, so it is an asynchronous operation. To preserve order of calls, you need to await the result of this call:
void changeWeek() async {
// ...
await FirebaseFirestore.instance
.collection(widget.user.user.uid)
.doc(documentName)
.update({"activities": act});
}
Note that you need do declare the changeWeek() function as async for this to work.

How can you reload data that is generated through Builder BlocConsumer?

I tried to write my own action Future using . clear() and re-generate it in the same place, but it didn't work.
For example, it first generates data for the month of the last image (August), selects May and it clears August data and generates for May.
To explain: I get data for several months or years, for example: August 2022, May 2022, December 2021, etc.
To make the code more optimized I want to generate first for the last incoming item, and then when I click on a certain month in the dropdown, deleting the old data to generate new data for the month and year he chose.
#override
Widget build(BuildContext context) {
final _provider = Provider.of<MapRepository>(context);
currentIndicator = _provider.fieldIndicator;
filterLayer = _provider.filterLayer;
selectedMonth = currentIndicator != null ? currentIndicator!.getMonth : "";
selectedYear = currentIndicator != null ? currentIndicator!.getYear : "";
String dateMonth =
currentIndicator != null ? "$selectedMonth $selectedYear" : "Загрузка";
_controller = FixedExtentScrollController(initialItem: 0);
return BlocConsumer(
bloc: indicatorBloc,
listener: (context, state) {
if (state is FetchedIndicatorsState) {
int lastPresent = 0;
Future.delayed(Duration(seconds: 1)).then((value) {
for (int i = 0; i < indicators.length; i++) {
if (indicators.reversed.toList()[i].isPresent) {
lastPresent = i;
}
dates.add(indicators[i].getDateTime);
}
for (var date in dates) {
String shortMonth = DateFormat("MMM", "ru").format(date);
String year = DateFormat("yy", "ru").format(date);
String month =
DateFormat("MMMM", "ru").format(date).toCapitalized();
indicatorDates['$shortMonth$year'] = '$month ${date.year}';
}
selectIndicator(indicators.reversed.toList()[lastPresent]);
});
}
},
builder: (context, state) {
if (state is FetchedIndicatorsState) {
indicators = state.indicators;
for (int i = 0; i < indicators.length; i++) {
if (indicators[i].getMonth == selectedMonth &&
indicators[i].getYear == selectedYear) {
childrenIndicators.add(buildIndicator(
indicators[i], indicators[(i - 1 < 0) ? 0 : (i - 1)], i));
}
}
return buildBody(context, dateMonth, childrenIndicators);
}
return Container();
},
);
}
OnTap actions:
onTap: () {
_refreshData();
setState(() {
selectedYear = entry.value.substring(entry.value.length - 5);
selectedMonth = entry.value.substring(0, entry.value.length - 5);
});
Navigator.pop(context);
},
My action:
Future _refreshData() async {
await Future.delayed(Duration(seconds: 3));
childrenIndicators.clear();
for (int i = 0; i < indicators.length; i++) {
if (indicators[i].getMonth == selectedMonth &&
indicators[i].getYear == selectedYear) {
childrenIndicators.add(buildIndicator(
indicators[i], indicators[(i - 1 < 0) ? 0 : (i - 1)], i));
}
}
setState(() {});
}

Flutter health: ^3.4.4 - getTotalStepsInInterval

i have problem with package health 3.4.4.
I need use this code a rebuild to other activities like BLOOD_OXYGEN or ACTIVE_ENERGY_BURNED :
This code is ok:
fetchStepBar() async {
int? steps;
int hour = 0;
int minute = 0;
int second = 0;
int millisecond = 0;
int microsecond = 0;
final midnight1 = selectedDate == null
? DateTime(now.year, now.month, now.day)
: DateTime(selectedDate!.year, selectedDate!.month, selectedDate!.day);
final stepstimefetch1 = selectedDate == null
? now
: DateTime(selectedDate!.year, selectedDate!.month, selectedDate!.day,
hour = 23, minute = 59, second = 59);
bool requested = await health.requestAuthorization([HealthDataType.STEPS]);
if (requested) {
try {
steps =
await health.getTotalStepsInInterval(midnight1, stepstimefetch1);
} catch (error) {
print("Caught exception in getTotalStepsInInterval: $error");
}
setState(() {
_nofStepsday = (steps == null) ? 0 : steps;
});
}
}
I see problem in: health.getTotalStepsInInterval
I tried rebuild code in class HealthFactory:
Future<int?> getTotalActive_energy_burnedInInterval(
DateTime startDate,
DateTime endDate,
) async {
final args = <String, dynamic>{
'startDate': startDate.millisecondsSinceEpoch,
'endDate': endDate.millisecondsSinceEpoch
};
final energy = await _channel.invokeMethod<int?>(
'getTotalActive_energy_burnedInInterval',
args,
);
return energy;
}
But!!! The problem I cannot solve is method channel -> 'getTotalActive_energy_burnedInInterval' It didn't works for me. I cannot definite this.
Can anybody help me solve this problem?
Thanks a lot

Date Comparison in Dart/Flutter

I am trying to compare two DateTimes in flutter and execute a particular function using if statements. However, I have been getting NoSuchMethodError.
Here is my code:
DateTime _myNowTime; DateTime _myClickTime
_getClickTime()async{ FirebaseUser currentUser = await
FirebaseAuth.instance.currentUser();
Firestore.instance.collection('user').document(currentUser.uid).snapshots().listen((event) {
if(event.data.isNotEmpty){ setState(() { _now_time = event['now_time'];
_click_time = event['click_time']; _myNowTime = _now_time.toDate(); _myClickTime = _click_time.toDate();
});
} }); }
I want to create a function:
checkTime(){
if(_myNowTime.compareTo(_myClickTime) >= 30 minutes){
//do something ...}
}
void main() {
var now = DateTime.now();
var yesterday = now.subtract(const Duration(days: 1));
if(now == yesterday) {
print("Dates are the same");
} else print("Dates are not the same");
}

Sort out dates for flutter check box/ Date scheduler

I have a service which returns a list of dates, which the user can opt for a future payment.
In the UI, there are three drop down boxes, one each for year, month and date.
Now when the user selects a particular year, then the months shown in the next drop down should only contain months corresponding to that particular selected year and similarly when the month is selected only the corresponding dates to that particular selected month should be shown.
The service response is something like below :
[
{
"availableDate":"03/13/2020"
},
{
"availableDate":"04/14/2020"
},
{
"availableDate":"01/15/2020"
},
{
"availableDate":"01/16/2020"
},
{
"availableDate":"02/17/2020"
},
{
"availableDate":"02/18/2020"
},
{
"availableDate":"02/22/2021"
}
]
I was able to split out the dates,months and years and when I tried to change values using onChange, didn't get the desired result. Could some one please help me with the logic or maybe give me a link to get started?
I have found out a solution.
First initialize the variables :
List _serviceData = [];
List _yearList = [];
List _monthList = [];
List _dateList = [];
List<SchedulerYear> _yearData = new List<SchedulerYear>();
List<SchedulerMonth> _monthData = new List<SchedulerMonth>();
List<SchedulerDate> _dateData = new List<SchedulerDate>();
var yearData = [];
var monthData = [];
var _loadData, _year, _month, _date;
Models used :
class SchedulerYear {
String year;
String month;
String date;
SchedulerYear({this.year,this.month,this.date});
#override
String toString() {
return '$year $month $date';
}
}
class SchedulerMonth {
String month;
String date;
SchedulerMonth({this.month,this.date});
#override
String toString() {
return '$month $date';
}
}
class SchedulerDate {
String date;
SchedulerDate({this.date});
#override
String toString() {
return '$date';
}
}
And finally the functions :
List<DropdownMenuItem<String>> getMenuItems(List options) {
List<DropdownMenuItem<String>> items = List();
for (String n in options) {
items.add(DropdownMenuItem(value: n, child: Text(n)));
}
return items;
}
_getYears() async {
_serviceData = await serviceHandler.fadfj; // the service response as a List
_yearData = [];
_yearList = [];
_yearItems = [];
for (int i = 0; i < _serviceData.length; i++) {
_loadData = _serviceData[i].toString();
_month = _loadData.split('/')[0];
_date = _loadData.split('/')[1];
_year = _loadData.split('/')[2];
_yearData.add(SchedulerYear(year: _year, month: _month, date: _date));
_yearList.add(_year);
}
_yearList = _yearList.toSet().toList();
_yearItems = getMenuItems(_yearList);
_selectedYear = _yearItems[0].value;
yearData = _yearData;
}
_getMonths(selectedYear) {
_dateItems = [];
_dateItems = getMenuItems(_initialDate);
_selectedDate = _dateItems[0].value;
_yearData = yearData;
_monthData = [];
_monthList = [];
_monthItems = [];
for (int i = 0; i < _yearData.length; i++) {
if (_yearData[i].year == selectedYear) {
_monthData.add(SchedulerMonth(month: _yearData[i].month, date: _yearData[i].date));
_monthList.add(_yearData[i].month);
}
}
monthData = _monthData;
_monthList = _monthList.toSet().toList();
_monthItems = getMenuItems(_monthList);
_selectedMonth = _monthItems[0].value;
}
_getDates(selectedMonth) {
_monthData = monthData;
_dateData = [];
_dateList = [];
_dateItems = [];
for (int i = 0; i < _monthData.length; i++) {
if (_monthData[i].month == selectedMonth) {
_dateData.add(SchedulerDate(date: _monthData[i].date));
_dateList.add(_monthData[i].date);
}
}
_dateList = _dateList.toSet().toList();
_dateItems = getMenuItems(_dateList);
_selectedDate = _dateItems[0].value;
}
_getYears() is called inside init() and the _getMonths(selectedYear) is called onChange of years dropdown button and _getDates(selectedMonth) on the months dropdown button