Topic: What do I need to do to 'inherit' _flDetailData from EventBloc
Two files listed below LineChartEvents and EventBloc are setup to display a fl_charts line chart. LineChartEvents is the display page, and it is meant to get its data from the EventBloc routine getChartData()
LineChartEvents page puts up an line chart using the data stored in List _flDetailData after executing
ChartData(
startDate: '1638700000000',
endDate: '2638700000000',
).getChartData();
in init() - but it is always empty.
EventBloc routine getChartData() successfully pulls the data from firestore and populates List _flDetailData inside EventBloc with FLSpots.
This code runs, but _flDetailData is empty when I try to use it in build().
Please help
Good morning, afternoon, or evening and best regards,
Jaz
Thanks
PS: don't have a server to link so code is in-line below
======================= LineChartEvents ========================
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:se_app/blocs/event_rollup_bloc.dart';
import 'package:provider/provider.dart';
import 'package:se_app/pages/charts/chart_data.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:se_app/pages/charts/chart_data';
class LineChartEvents extends StatefulWidget {
const LineChartEvents({Key? key}) : super(key: key);
@override
_LineChartEventsState createState() => _LineChartEventsState();
}
class _LineChartEventsState extends State<LineChartEvents> {
List<Color> gradientColors = [
const Color(0xff23b6e6),
const Color(0xff02d39a),
];
List _data = [];
List<FlSpot> flData = [];
int index = 0;
int _duration = 0;
String _eventTitle = '';
int _timestampInt = 0;
String _timestampIntStr = '';
String _dateNowStr = '';
Timestamp _timestamp = Timestamp.now();
int _day = 0;
int _month = 0;
int _year = 0;
int _hour = 0;
int _minute = 0;
int _seconds = 0;
List<FlSpot> _flDetailData = [];
@override
initState() {
super.initState();
ChartData(
startDate: '1638700000000',
endDate: '2638700000000',
).getChartData();
}
bool showAvg = false;
Future _getDate() async {
final DateTime _nowDT = DateTime.now();
_timestamp = Timestamp.now();
_timestampInt = Timestamp.now().millisecondsSinceEpoch;
_timestampIntStr = _timestampInt.toString().substring(0, 13);
final dateStrSegments = _dateNowStr.split('-');
if (dateStrSegments.length == 6) {
_year = int.tryParse(dateStrSegments[0])!;
_month = int.tryParse(dateStrSegments[1])!;
_day = int.tryParse(dateStrSegments[2])!;
_hour = int.tryParse(dateStrSegments[3])!;
_minute = int.tryParse(dateStrSegments[4])!;
_seconds = int.tryParse(dateStrSegments[5])!;
}
}
Duration swapAnimationDuration = const Duration(milliseconds: 150);
Curve swapAnimationCurve = Curves.linear;
@override
Widget build(BuildContext context) {
double w = MediaQuery.of(context).size.width;
double h = MediaQuery.of(context).size.height;
return Container(
color: Colors.blueGrey,
child: Flex(
direction: Axis.vertical,
children: [
Container(
color: Colors.blueGrey,
width: w * .6,
height: 42,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 8,
primary:
showAvg ? Colors.black : Colors.white.withOpacity(0.5)),
onPressed: () {
setState(() {
showAvg = !showAvg;
});
},
child: Text(
showAvg ? 'Per Day Average' : 'Per Day Detail',
style: TextStyle(
fontSize: 24,
color:
showAvg ? Colors.white.withOpacity(0.5) : Colors.black),
),
),
),
AspectRatio(
aspectRatio: 1.70,
child: Container(
height: 120,
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(18),
),
color: Color(0xff232d37)),
child: Padding(
padding: const EdgeInsets.only(
right: 18.0, left: 12.0, top: 12, bottom: 12),
child: LineChart(
showAvg ? avgData(_flDetailData) : mainData(_flDetailData),
),
),
),
),
],
),
);
}
LineChartData mainData(flDetailData) {
final EventRollupBloc eventRollupBloc =
Provider.of<EventRollupBloc>(context);
eventRollupBloc.getChartSeries(10, Timestamp(10000000, 1000000), 200, 20);
return LineChartData(
gridData: FlGridData(
show: true,
drawVerticalLine: true,
getDrawingHorizontalLine: (value) {
return FlLine(
color: const Color(0xff37434d),
strokeWidth: 1,
);
},
getDrawingVerticalLine: (value) {
return FlLine(
color: const Color(0xff37434d),
strokeWidth: 1,
);
},
),
titlesData: FlTitlesData(
show: true,
rightTitles: SideTitles(showTitles: false),
topTitles: SideTitles(showTitles: true),
bottomTitles: SideTitles(
showTitles: true,
reservedSize: 22,
interval: 1,
getTextStyles: (context, value) => const TextStyle(
color: Color(0xff68737d),
fontWeight: FontWeight.bold,
fontSize: 16),
getTitles: (value) {
switch (value.toInt()) {
case 2:
return 'MAR';
case 5:
return 'JUN';
case 8:
return 'SEP';
}
return '';
},
margin: 8,
),
leftTitles: SideTitles(
showTitles: true,
interval: 1,
getTextStyles: (context, value) => const TextStyle(
color: Color(0xff67727d),
fontWeight: FontWeight.bold,
fontSize: 15,
),
getTitles: (value) {
switch (value.toInt()) {
case 1:
return '10';
case 3:
return '30';
case 5:
return '50';
}
return '';
},
reservedSize: 32,
margin: 12,
),
),
borderData: FlBorderData(
show: true,
border: Border.all(color: const Color(0xff37434d), width: 1),
),
minX: 0,
maxX: 20,
minY: 0,
maxY: 20,
lineBarsData: [
LineChartBarData(
spots: _flDetailData,
// const [
// FlSpot(0, 3),
// FlSpot(2.6, 2),
// FlSpot(4.9, 5),
// FlSpot(6.8, 3.1),
// FlSpot(8, 4),
// FlSpot(9.5, 3),
// FlSpot(11, 4),
// ],
isCurved: true,
colors: gradientColors,
barWidth: 5,
isStrokeCapRound: true,
dotData: FlDotData(
show: false,
),
belowBarData: BarAreaData(
show: true,
colors:
gradientColors.map((color) => color.withOpacity(0.3)).toList(),
),
),
],
);
}
LineChartData avgData(flDetailData) {
return LineChartData(
lineTouchData: LineTouchData(enabled: false),
gridData: FlGridData(
show: true,
drawHorizontalLine: true,
getDrawingVerticalLine: (value) {
return FlLine(
color: const Color(0xff37434d),
strokeWidth: 1,
);
},
getDrawingHorizontalLine: (value) {
return FlLine(
color: const Color(0xff37434d),
strokeWidth: 1,
);
},
),
titlesData: FlTitlesData(
show: true,
bottomTitles: SideTitles(
showTitles: true,
reservedSize: 22,
getTextStyles: (context, value) => const TextStyle(
color: Color(0xff68737d),
fontWeight: FontWeight.bold,
fontSize: 16),
getTitles: (value) {
switch (value.toInt()) {
case 2:
return 'MAR';
case 5:
return 'JUN';
case 8:
return 'SEP';
}
return '';
},
margin: 8,
interval: 1,
),
leftTitles: SideTitles(
showTitles: true,
getTextStyles: (context, value) => const TextStyle(
color: Color(0xff67727d),
fontWeight: FontWeight.bold,
fontSize: 15,
),
getTitles: (value) {
switch (value.toInt()) {
case 1:
return '10k';
case 3:
return '30k';
case 5:
return '50k';
}
return '';
},
reservedSize: 32,
interval: 1,
margin: 12,
),
topTitles: SideTitles(showTitles: false),
rightTitles: SideTitles(showTitles: false),
),
borderData: FlBorderData(
show: true,
border: Border.all(color: const Color(0xff37434d), width: 1)),
minX: 0,
maxX: 11,
minY: 0,
maxY: 6,
lineBarsData: [
LineChartBarData(
spots: const [
FlSpot(0, 3.44),
FlSpot(2.6, 3.44),
FlSpot(4.9, 3.44),
FlSpot(6.8, 3.44),
FlSpot(8, 3.44),
FlSpot(9.5, 3.44),
FlSpot(11, 3.44),
],
isCurved: true,
colors: [
ColorTween(begin: gradientColors[0], end: gradientColors[1])
.lerp(0.2)!,
ColorTween(begin: gradientColors[0], end: gradientColors[1])
.lerp(0.2)!,
],
barWidth: 5,
isStrokeCapRound: true,
dotData: FlDotData(
show: false,
),
belowBarData: BarAreaData(show: true, colors: [
ColorTween(begin: gradientColors[0], end: gradientColors[1])
.lerp(0.2)!
.withOpacity(0.1),
ColorTween(begin: gradientColors[0], end: gradientColors[1])
.lerp(0.2)!
.withOpacity(0.1),
]),
),
],
);
}
}
=========================================================
====================== EventBloc ========================
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:se_app/blocs/profile_bloc.dart';
import 'package:se_app/models/charting_data.dart';
import 'package:shared_preferences/shared_preferences.dart';
// import 'package:fl_chart/fl_chart.dart';
class EventBloc extends ChangeNotifier {
init() {
// getEventLength();
getData();
}
EventBloc() {
// getEventLength();
getData();
}
String data = '';
String _date = '';
String get date => _date;
List _data = [];
List get eventData => _data;
List _filteredData = [];
List get filteredData => _filteredData;
bool _hasData = false;
bool get hasData => _hasData;
int _lastEventTimestampInt = 0;
String _lastEventType = '';
Timestamp _timestamp = Timestamp.now();
int _stopTimestampInt = 0;
int _timestampNowInt = 0;
int _eventDurationInt = 0;
String _durationDateStr = '';
String _timestampNowIntStr = '';
String _stopTimestampStr = '';
int _startEventTS = 0;
int _stopEventTS = 0;
String _eventDurationStr = '';
// bool _emoBool = false;
// charting series vars
List<charts.Series> seriesList = [];
bool animate = false;
int _duration = 0;
int _idx = 0;
int _upperRangeTS = 0;
int _lowerRangeTS = 0;
DateTime _upperRangeDT = DateTime.now();
DateTime _lowerRangeDT = DateTime.now();
int _day = 0;
int _month = 0;
int _year = 0;
int _hour = 0;
int _minute = 0;
int _seconds = 0;
String _eventType = 'Ready';
String _uid = '';
String _dateStrDDMMYYYYHHMMSS = 'DDMMYYYYHHMMSS';
String sessionDuration = '';
int sessionCost = 0;
int _eventLength = 0;
int get eventLength => _eventLength;
int _savedNlength = 0;
int get savedNlength => _savedNlength;
int _eventFinalLength = 0;
int get eventFinalLength => _eventFinalLength;
Future getData() async {
// TODO: JME #1 -
final SharedPreferences _sp = await SharedPreferences.getInstance();
_uid = _sp.getString('uid')!;
// setEventDurationString();
QuerySnapshot snap = await FirebaseFirestore.instance
.collection('event')
.where("uid", isEqualTo: _uid)
.orderBy("timestamp", descending: false)
.limit(1000)
.get();
var x = snap.docs;
_data.clear();
for (var f in x) {
_data.add(f);
}
// _data.sort((a, b) => a['timestamp'].compareTo(b['timestamp']));
notifyListeners();
}
Future saveData(eventType, time) async {
// TODO: JME #1 -
SharedPreferences sp = await SharedPreferences.getInstance();
String? _uid = sp.getString('uid');
final ProfileBloc pb = ProfileBloc();
_timestampNowInt = Timestamp.now().millisecondsSinceEpoch;
_timestampNowIntStr = _timestampNowInt.toString();
await FirebaseFirestore.instance.collection('event').doc().set(
{
"uid": _uid,
"timestamp": _timestampNowIntStr,
"year": _year,
"month": _month,
"day": _day,
"hour": _hour,
"minute": _minute,
"seconds": _seconds,
"eventType": eventType
},
SetOptions(merge: false),
);
// _emoBool = eventType.toString().substring(0, 3) == 'Emo';
if (eventType == 'Live' || eventType == 'Smoke') {
//TODO: JME EMO && _emoBool != true) {
_lastEventTimestampInt = _timestampNowInt;
_lastEventType = eventType;
}
if (eventType == 'Stop' || eventType == 'Complete') {
//TODO: JME Emo - || _emoBool} {
setEventDurationString();
await FirebaseFirestore.instance.collection('eventRollup').doc().set(
{
"uid": _uid,
"timestamp": _timestampNowIntStr,
// "duration": _emoBool ? '0' : _eventDurationStr,
"duration": _eventDurationStr,
"year": _year,
"month": _month,
"day": _day,
"hour": _hour,
"minute": _minute,
"seconds": _seconds,
// "eventType": _emoBool ? eventType : _lastEventType
"eventType": _lastEventType
},
SetOptions(merge: false),
);
// .then(
// //TODO: JME #1 (value) => {pb.saveStatistics()},
// );
// set eventTypes to current event
// _eventType = '';
// _lastEventType = '';
// _lastEventTimestampInt = 0;
}
// getData();
}
Future setEventDurationString() async {
// _eventDurationStr = _duration.toString();
_stopTimestampInt = Timestamp.now().millisecondsSinceEpoch;
_eventDurationInt = _timestampNowInt - _lastEventTimestampInt;
String aStr = DateFormat('yyyy-mm-dd-hh-mm-ssmmm')
.format(DateTime.fromMillisecondsSinceEpoch(_eventDurationInt));
_eventDurationStr = _eventDurationInt.toString();
// split out date segments toInts for storage
// reason is to speed up queries for charting
// by day month and year
final dateStrSegments = aStr.split('-');
if (dateStrSegments.length == 6) {
_year = int.tryParse(dateStrSegments[0])!;
_month = int.tryParse(dateStrSegments[1])! + 1;
_day = int.tryParse(dateStrSegments[2])!;
_hour = int.tryParse(dateStrSegments[3])!;
_minute = int.tryParse(dateStrSegments[4])!;
_seconds = int.tryParse(dateStrSegments[5].substring(0, 2))!;
// }
}
Future deleteEvent(uid, timestamp) async {
FirebaseFirestore.instance
.collection('event/$timestamp')
.doc('$uid$timestamp')
.delete();
getData();
}
//charting routines
void setRange(_startTimestamp, _duration, _period) {
// Timestamp _ts = Timestamp.now();
int _tsInt = Timestamp.now().millisecondsSinceEpoch;
String _tsStr = Timestamp.now().toString();
DateTime _tsDate = Timestamp.now().toDate();
var now = DateTime.now();
var _lowerRange =
now.subtract(Duration(days: chartPeriodDays[_idx] * _duration));
int _durMS = chartPeriod[_idx] * _duration;
_upperRangeTS = _tsInt;
}
Future getChartSeries(
_period, _startTimestamp, _duration, _pagingListSize) async {
if (chartPeriod.contains(_period)) {
_idx = chartPeriod.indexOf(_period);
setRange(_startTimestamp, _duration, _period);
} else {
//TODO: implement custom range
// return default _period of a week in 7 stacks
_period = 'Week';
_idx = 2;
_duration = 1;
_pagingListSize = 100;
setRange(_startTimestamp, _duration, _period);
}
// get user uid
SharedPreferences sp = await SharedPreferences.getInstance();
String? _uid = sp.getString('uid');
// get data >=< range
// setEventDurationString();
QuerySnapshot snap = await FirebaseFirestore.instance
.collection('event')
.where("uid", isEqualTo: _uid)
.orderBy("timestamp", descending: true)
.get();
var x = snap.docs;
_data.clear();
for (var f in x) {
_data.add(f);
}
// _data.sort((a, b) => b['timestamp'].compareTo(a['timestamp']));
// notifyListeners();
}
}
}