Somethings, idk what I made
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
import 'package:tasktracker/AvgDay.dart';
|
||||
import 'package:tasktracker/main.dart';
|
||||
|
||||
@@ -16,9 +17,30 @@ class AnalyticsPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _AnalyticsPageState extends State<AnalyticsPage> {
|
||||
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<Activity> avgDayActs = AnalyticTools.getAverageDayActs(DateTimeRange(start: DateTime.now().subtract(Duration(days:7)),end: DateTime.now()));
|
||||
List<CatMapData> avgDayData =[];
|
||||
Map<Category, int> avgTime = <Category,int>{};
|
||||
|
||||
for (var act in avgDayActs) {
|
||||
if(avgTime.containsKey(act.taskType.cat!)){
|
||||
int _val = avgTime[act.taskType.cat!]!;
|
||||
avgTime.update(act.taskType.cat!, (value) => _val + act.endTime.difference(act.startTime).inMinutes);
|
||||
}else{
|
||||
avgTime.putIfAbsent(act.taskType.cat!, () => act.endTime.difference(act.startTime).inMinutes);
|
||||
}
|
||||
}
|
||||
int trackedTime = 0;
|
||||
avgTime.forEach((key, value) {
|
||||
avgDayData.add(CatMapData(key.name, value, HexColor.fromHex(key.color)));
|
||||
trackedTime+= value;
|
||||
});
|
||||
|
||||
avgDayData.add(CatMapData('Untracked', 1440-trackedTime, Colors.black));
|
||||
// for (var value in avgActs) {
|
||||
// Debug.LogResponse('${value.taskType.name} : ${DateFormat('HH:mm').format(value.startTime)} - ${DateFormat('HH:mm').format(value.endTime)}');
|
||||
// }
|
||||
@@ -51,7 +73,29 @@ class _AnalyticsPageState extends State<AnalyticsPage> {
|
||||
],
|
||||
),
|
||||
Divider(),
|
||||
Container(
|
||||
height: 400,
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: (!days.isEmpty)
|
||||
? Column(
|
||||
children: [
|
||||
|
||||
Expanded(
|
||||
child: SfCircularChart(legend: Legend(isVisible: true,position: LegendPosition.bottom,overflowMode: LegendItemOverflowMode.wrap), series: <CircularSeries>[
|
||||
// Render pie chart
|
||||
PieSeries<CatMapData, String>(
|
||||
dataSource: avgDayData,
|
||||
pointColorMapper: (CatMapData data, _) => data.color,
|
||||
xValueMapper: (CatMapData data, _) => data.name,
|
||||
yValueMapper: (CatMapData data, _) => data.time,
|
||||
dataLabelMapper: (CatMapData sales, _) => MinutesToTimeString(sales.time),
|
||||
dataLabelSettings: DataLabelSettings(isVisible: true, useSeriesColor: true, overflowMode: OverflowMode.shift, showZeroValue: false))
|
||||
]))
|
||||
],
|
||||
)
|
||||
: Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: [CircularProgressIndicator()]))),
|
||||
|
||||
],
|
||||
),
|
||||
@@ -66,9 +110,42 @@ class _AnalyticsPageState extends State<AnalyticsPage> {
|
||||
|
||||
class AnalyticTools{
|
||||
|
||||
static double dailyThreshold = 0.9;
|
||||
static int activityGroupingThreshold = 4;
|
||||
static Map<DateTime, double> getProductivities(DateTimeRange _range){
|
||||
DateTimeRange range = DateTimeRange(start: DateTime(_range.start.year, _range.start.month,_range.start.day, 0,0,0), end: DateTime(_range.end.year, _range.end.month,_range.end.day, 23,59,59));
|
||||
Map<DateTime, double> prodData = <DateTime, double>{};
|
||||
Map<DateTime, int> prodActs = <DateTime, int>{};
|
||||
Debug.Log("Calculating productivity between ${range.start} - ${range.end}");
|
||||
//PASS 1: Split Activities into prod and unprod
|
||||
for (var activity in User.activities) {
|
||||
if(activity.startTime.isAfter(range.start) && activity.endTime.isBefore(range.end)){
|
||||
//Eligible for anal
|
||||
DateTime day = DateTime(activity.startTime.year, activity.startTime.month, activity.startTime.day);
|
||||
if(activity.taskType!.cat!.productive){
|
||||
if(prodActs.containsKey(day)){
|
||||
int _prod = prodActs[day] ?? 0;
|
||||
prodActs.update(day, (value) => _prod +activity.endTime.difference(activity.startTime).inMinutes);
|
||||
}else{
|
||||
prodActs.putIfAbsent(day, () => activity.endTime.difference(activity.startTime).inMinutes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//PASS 2: Calculate productivity percentage and add them into a list
|
||||
for(int i = 0; i <= range.end.difference(range.start).inDays; i++){
|
||||
DateTime day = DateTime(range.start.add(Duration(days: i)).year,range.start.add(Duration(days: i)).month,range.start.add(Duration(days: i)).day);
|
||||
|
||||
double productivity = ((prodActs[day] ?? 0) / 1440) * 100;
|
||||
Debug.LogTest('productivity @ $day = $productivity');
|
||||
prodData.putIfAbsent(day, () => productivity);
|
||||
|
||||
}
|
||||
|
||||
return prodData;
|
||||
}
|
||||
|
||||
static double dailyThreshold = 0.9;
|
||||
static int activityGroupingThreshold = 5;
|
||||
|
||||
static List<Activity> getAverageDayActs(DateTimeRange range){
|
||||
int totalDays = range.end.difference(range.start).inDays;
|
||||
|
||||
@@ -16,7 +16,7 @@ class AvgDayPage extends StatefulWidget {
|
||||
|
||||
class _AvgDayPageState extends State<AvgDayPage> {
|
||||
DateFormat dFormat = DateFormat('HH:mm');
|
||||
DateTimeRange dateRange = DateTimeRange(start: DateTime.now().subtract(Duration(days: 7)), end: DateTime.now());
|
||||
DateTimeRange dateRange = DateTimeRange(start: DateTime.now().subtract(Duration(days: 8)), end: DateTime.now().subtract(Duration(days: 1)));
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<Activity> avgActs = AnalyticTools.getAverageDayActs(dateRange);
|
||||
|
||||
@@ -54,7 +54,9 @@ class _TodosPageState extends State<TodosPage> {
|
||||
Widget build(BuildContext context) {
|
||||
projects = <String, List<Todo>>{};
|
||||
simpleTodos = [];
|
||||
for (var todo in User.todos) {
|
||||
List<Todo> todos = User.todos;
|
||||
todos.sort((a,b)=> a.dueDate.compareTo(b.dueDate));
|
||||
for (var todo in todos) {
|
||||
if (todo.task!.relatedProject != null) {
|
||||
String projectName = todo.task!.relatedProject!.name;
|
||||
if (projects.containsKey(projectName)) {
|
||||
|
||||
@@ -99,9 +99,12 @@ Future<void> BuildBridgeToServer() async {
|
||||
(await http.post(Uri.parse('http://161.97.127.136/task_tracker/bridge.php'), body: <String, String>{"username": username}));
|
||||
|
||||
Debug.LogResponse("${response.body}",src: 'bridge');
|
||||
|
||||
List<String> data = response.body.split(",");
|
||||
Debug.LogResponse('Update :\nactivities_rev=${data[0]} tasks_rev=${data[1]} cats_rev=${data[2]} projects_rev=${data[3]}');
|
||||
|
||||
bool changedOffline = offline==true;
|
||||
offline=false;
|
||||
if(changedOffline){refreshStream.add(false);}
|
||||
if (data[4].contains('<td>')) {
|
||||
List<String> ongoingData = data[4].split("<td>");
|
||||
if (!prefs.containsKey('current_activity')) {
|
||||
@@ -125,6 +128,9 @@ Future<void> BuildBridgeToServer() async {
|
||||
}
|
||||
} catch (e) {
|
||||
Debug.LogError("Error with bridge : $e");
|
||||
bool changedOffline = offline == false;
|
||||
offline=true;
|
||||
if(changedOffline){refreshStream.add(false);}
|
||||
}
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
}
|
||||
|
||||
839
lib/main.dart
839
lib/main.dart
@@ -129,6 +129,15 @@ DateTime? lastDay = null;
|
||||
DateTimeRange? taskTypeRange = null;
|
||||
DateTimeRange? catsRange = null;
|
||||
DateTimeRange? prodRange = null;
|
||||
|
||||
|
||||
List<ProductivityMapData> pastProductivityData = <ProductivityMapData>[
|
||||
ProductivityMapData('02/24', 32),
|
||||
ProductivityMapData('02/25', 5),
|
||||
ProductivityMapData('02/26',56),
|
||||
ProductivityMapData('02/27', 33),
|
||||
ProductivityMapData('02/28', 50)
|
||||
];
|
||||
List<ProductivityMapData> productivityData = <ProductivityMapData>[
|
||||
ProductivityMapData('02/24', 35),
|
||||
ProductivityMapData('02/25', 28),
|
||||
@@ -473,6 +482,13 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
// }
|
||||
}
|
||||
|
||||
//Past Prod
|
||||
Map<DateTime, double> pastProdData = AnalyticTools.getProductivities(DateTimeRange(start: prodRange!.start.subtract(Duration(days: prodRange!.duration.inDays+1)), end: prodRange!.start.subtract(Duration(days: 1))));
|
||||
pastProductivityData=[];
|
||||
pastProdData.forEach((key, value) {
|
||||
pastProductivityData.add(ProductivityMapData(dFormat.format(key.add(Duration(days: prodRange!.duration.inDays+1))), value));
|
||||
});
|
||||
|
||||
taskTypesDuration.forEach((key, value) {
|
||||
print("$key : $value");
|
||||
taskTypesData.add(TaskTypeMapData(key.name, value, HexColor.fromHex(key.cat!.color)));
|
||||
@@ -532,6 +548,23 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
double avgProd = 0;
|
||||
double pastAvgProd = 0;
|
||||
int _avgProdCount = 0;
|
||||
int _pastAvgProdCount = 0;
|
||||
productivityData.forEach((element) {
|
||||
avgProd += element.productivity;
|
||||
_avgProdCount++;
|
||||
});
|
||||
|
||||
pastProductivityData.forEach((element) {
|
||||
pastAvgProd += element.productivity;
|
||||
_pastAvgProdCount++;
|
||||
});
|
||||
|
||||
avgProd = avgProd / _avgProdCount;
|
||||
pastAvgProd = pastAvgProd / _pastAvgProdCount;
|
||||
return Scaffold(
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
onPressed: () {
|
||||
@@ -571,400 +604,446 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
)),
|
||||
drawer: navDrawer(context, 0),
|
||||
body: SafeArea(
|
||||
child: (User.activities.isEmpty) ? Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center
|
||||
,children:[
|
||||
Expanded(flex: 1,child: Container(),),
|
||||
Expanded(flex: 2,child: Image(image: AssetImage('images/empty.png'))),
|
||||
Expanded(flex:2,child: Text("Add your first activity to access Summary",style: TextStyle(color: Colors.grey, fontStyle: FontStyle.italic),))
|
||||
]) :Column(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
if(User.offline)Expanded(flex:1,child: Container(width:1000,color: Colors.red,child: Align(alignment: Alignment.center,child: Text("Offline")))),
|
||||
Expanded(
|
||||
flex:50,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: Column(
|
||||
children: [
|
||||
(false)
|
||||
? Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Text("Good\nMorning!", style: TextStyle(fontSize: 23, fontStyle: FontStyle.italic)),
|
||||
Text(
|
||||
"12%",
|
||||
style: TextStyle(fontSize: 30),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Text(DateFormat("yy - MM-dd").format(DateTime.now())),
|
||||
Text(DateFormat("HH:mm").format(DateTime.now()), style: TextStyle(fontSize: 40)),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
: Container(),
|
||||
//Ongoing activity card
|
||||
(ongoingActName == "") ? Container():
|
||||
Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Card(
|
||||
color: Colors.white12,
|
||||
elevation: 20,
|
||||
shadowColor: Colors.green,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 20),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
SpinKitPouringHourGlass(color: Colors.amber),
|
||||
SizedBox(width: 20,),
|
||||
Flexible(child: Text("You are engaged in '$ongoingActName' since ${DateFormat("hh:mm").format(ongoingActStime)}.", style: TextStyle(fontSize: 19),textAlign: TextAlign.center,)),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10,),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Container(
|
||||
child:Text(MinutesToTimeString(DateTime.now().difference(ongoingActStime).inMinutes))
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: (){
|
||||
Dialogs.ongoing();
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.green,
|
||||
borderRadius: BorderRadius.circular(10)
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 8,horizontal: 15),
|
||||
child:Text('Take Action')
|
||||
)
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
if(relativeTodos.isNotEmpty)Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Card(
|
||||
color: Colors.white10,
|
||||
elevation: 20,
|
||||
shadowColor: Colors.black,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('Close To-Do',style: TextStyle(fontSize: 16)),
|
||||
MaterialButton(height: 30,
|
||||
color: Colors.green,
|
||||
onPressed: (){
|
||||
Navigator.of(context).pushNamed('/Todos');
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Text('More'),
|
||||
Icon(Icons.keyboard_arrow_right)
|
||||
],
|
||||
),
|
||||
|
||||
)
|
||||
],
|
||||
),
|
||||
LimitedBox(
|
||||
maxHeight: 250,
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: relativeTodos.length,
|
||||
itemBuilder: (context, index){
|
||||
return Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
margin: EdgeInsets.symmetric(vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black26,
|
||||
borderRadius: BorderRadius.circular(10)
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
FittedBox(child: Text('${relativeTodos[index].task!.name} -> ${relativeTodos[index].metadata}')),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 5),
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(20), color: Colors.blue),
|
||||
child: Text(DateFormat('MM/dd').format(relativeTodos[index].dueDate))
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Card(
|
||||
color: Colors.white10,
|
||||
elevation: 20,
|
||||
shadowColor: Colors.black,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 20),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Container(width:100,height: 150,child: CustomPaint(painter: HourglassPainter(hourglassTime, hourglassColors, hourglassStops),)),
|
||||
Column(
|
||||
children: [
|
||||
Text(DateFormat("MMMM-dd").format(DateTime.now()),style:TextStyle(fontSize: 18)),
|
||||
Text(DateFormat("hh:mm a").format(DateTime.now()),style:TextStyle(fontSize: 40, fontWeight: FontWeight.bold)),
|
||||
Container(height: 20,)
|
||||
],
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
Container(
|
||||
height: 350,
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Card(
|
||||
color: Colors.white10,
|
||||
elevation: 20,
|
||||
shadowColor: Colors.black,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10,vertical: 0),
|
||||
((MediaQuery.of(context).size.width / MediaQuery.of(context).size.height) > 1) ?navDrawer(context, 0) : Container(),
|
||||
(User.activities.isEmpty) ? Container(
|
||||
width: 1000,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center
|
||||
,children:[
|
||||
Expanded(flex: 1,child: Container(),),
|
||||
Expanded(flex: 2,child: Image(image: AssetImage('images/empty.png'))),
|
||||
Expanded(flex:2,child: Text("Add your first activity to access Summary",style: TextStyle(color: Colors.grey, fontStyle: FontStyle.italic),))
|
||||
]),
|
||||
) :Expanded(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
if(User.offline)Expanded(flex:1,child: Container(width:1000,color: Colors.red,child: Align(alignment: Alignment.center,child: Text("Offline")))),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: Column(
|
||||
children: [
|
||||
(false)
|
||||
? Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Text("Productivity", style: TextStyle(color: Colors.green, fontWeight: FontWeight.bold)),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
DateTimeRange? value = await showDateRangePicker(context: context, firstDate: firstDay ?? DateTime.now(), lastDate: lastDay ?? DateTime.now());
|
||||
if (value != null) {
|
||||
prodRange = value;
|
||||
}
|
||||
|
||||
LoadStats();
|
||||
},
|
||||
child: Text((prodRange != null) ? (DateFormat("MM/dd").format(prodRange!.start) + " - " + DateFormat("MM/dd").format(prodRange!.end)) : 'n/a'),
|
||||
Text("Good\nMorning!", style: TextStyle(fontSize: 23, fontStyle: FontStyle.italic)),
|
||||
Text(
|
||||
"12%",
|
||||
style: TextStyle(fontSize: 30),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Text(DateFormat("yy - MM-dd").format(DateTime.now())),
|
||||
Text(DateFormat("HH:mm").format(DateTime.now()), style: TextStyle(fontSize: 40)),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Divider(),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text("Today : "),
|
||||
Text("${(productivityData.length > 0) ? productivityData[0].productivity.toStringAsFixed(1) : 'n/a'}%",
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: (productivityData.length > 1)
|
||||
? ((productivityData[0].productivity > productivityData[1].productivity) ? Colors.lightGreenAccent : Colors.red)
|
||||
: Colors.white))
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text("Yesterday : "),
|
||||
Text("${(productivityData.length > 1) ? productivityData[1].productivity.toStringAsFixed(1) : 'n/a'}%", style: TextStyle(fontSize: 18))
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: SfCartesianChart(
|
||||
// Initialize category axis
|
||||
primaryXAxis: CategoryAxis(),
|
||||
series: <LineSeries<ProductivityMapData, String>>[
|
||||
LineSeries<ProductivityMapData, String>(
|
||||
// Bind data source
|
||||
markerSettings: MarkerSettings(isVisible: true, shape: DataMarkerType.circle),
|
||||
dataSource: productivityData.reversed.toList(),
|
||||
xValueMapper: (ProductivityMapData sales, _) => DateFormat('MM-dd').format(dFormat.parse(sales.day)),
|
||||
yValueMapper: (ProductivityMapData sales, _) => sales.productivity,
|
||||
dataLabelMapper: (ProductivityMapData sales, _) => sales.productivity.toStringAsFixed(1) + "%",
|
||||
dataLabelSettings: DataLabelSettings(overflowMode: OverflowMode.hide, showZeroValue: false, isVisible: true),
|
||||
onPointTap: (ChartPointDetails point){
|
||||
Dialogs.showJournalLink(dFormat.parse(productivityData[productivityData.length-point.pointIndex!-1].day));
|
||||
//showAlertDialog(context, productivityData[point.pointIndex!].day, "I'll show you detailed info about this day in future, When my master creates the feature");
|
||||
},
|
||||
pointColorMapper: (ProductivityMapData sales, _)=> (User.journalExists(dFormat.parse(sales.day)) ? Colors.lightGreenAccent : Colors.green)
|
||||
)
|
||||
//color: User.journalExists(dFormat.parse(productivityData[(productivityData.length-point.pointIndex!-1) as int].day)) ?Colors.green : Colors.red,
|
||||
]),
|
||||
),
|
||||
SizedBox(height: 20,),
|
||||
if(lastProductive!=null && DateTime.now().difference(lastProductive!).inMinutes > 60)RichText(text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(text: "You haven't been productive in last",style: TextStyle(color:Colors.orange)),
|
||||
TextSpan(text:" ${MinutesToTimeString(DateTime.now().difference(lastProductive!).inMinutes)}",style: TextStyle(color:Colors.redAccent,fontWeight: FontWeight.bold))
|
||||
]
|
||||
))
|
||||
|
||||
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
Container(
|
||||
height: 400,
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Card(
|
||||
color: Colors.white10,
|
||||
elevation: 20,
|
||||
shadowColor: Colors.black,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: (!days.isEmpty)
|
||||
? Column(
|
||||
)
|
||||
: Container(),
|
||||
//Ongoing activity card
|
||||
(ongoingActName == "") ? Container():
|
||||
Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Card(
|
||||
color: Colors.white12,
|
||||
elevation: 20,
|
||||
shadowColor: Colors.green,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 20),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||
Padding(padding: EdgeInsets.all(20), child: Text('Daily Briefing', style: TextStyle(fontWeight: FontWeight.bold))),
|
||||
dayPickerWidget(days, value: curDay, onChange: (_value) {
|
||||
print('new val : $_value');
|
||||
curDay = _value;
|
||||
setState(() {
|
||||
LoadStats();
|
||||
});
|
||||
}),
|
||||
]),
|
||||
Expanded(
|
||||
child: SfCircularChart(legend: Legend(isVisible: true,position: LegendPosition.bottom,overflowMode: LegendItemOverflowMode.wrap), series: <CircularSeries>[
|
||||
// Render pie chart
|
||||
PieSeries<CatMapData, String>(
|
||||
dataSource: dailyData,
|
||||
pointColorMapper: (CatMapData data, _) => data.color,
|
||||
xValueMapper: (CatMapData data, _) => data.name,
|
||||
yValueMapper: (CatMapData data, _) => data.time,
|
||||
dataLabelMapper: (CatMapData sales, _) => MinutesToTimeString(sales.time),
|
||||
dataLabelSettings: DataLabelSettings(isVisible: true, useSeriesColor: true, overflowMode: OverflowMode.shift, showZeroValue: false))
|
||||
]))
|
||||
SpinKitPouringHourGlass(color: Colors.amber),
|
||||
SizedBox(width: 20,),
|
||||
Flexible(child: Text("You are engaged in '$ongoingActName' since ${DateFormat("hh:mm").format(ongoingActStime)}.", style: TextStyle(fontSize: 19),textAlign: TextAlign.center,)),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10,),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Container(
|
||||
child:Text(MinutesToTimeString(DateTime.now().difference(ongoingActStime).inMinutes))
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: (){
|
||||
Dialogs.ongoing();
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.green,
|
||||
borderRadius: BorderRadius.circular(10)
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 8,horizontal: 15),
|
||||
child:Text('Take Action')
|
||||
)
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
: Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: [CircularProgressIndicator()])))),
|
||||
Container(
|
||||
height: (taskTypesData.length * 45).clamp(350, 1000).toDouble(),
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Card(
|
||||
color: Colors.white10,
|
||||
elevation: 20,
|
||||
shadowColor: Colors.black,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 25),
|
||||
child: Column(children: [
|
||||
Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||
Text("Task Types", style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
DateTimeRange? value = await showDateRangePicker(context: context, firstDate: firstDay ?? DateTime.now(), lastDate: lastDay ?? DateTime.now());
|
||||
if (value != null) {
|
||||
taskTypeRange = value;
|
||||
}
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
if(relativeTodos.isNotEmpty)Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Card(
|
||||
color: Colors.white10,
|
||||
elevation: 20,
|
||||
shadowColor: Colors.black,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('Close To-Do',style: TextStyle(fontSize: 16)),
|
||||
MaterialButton(height: 30,
|
||||
color: Colors.green,
|
||||
onPressed: (){
|
||||
Navigator.of(context).pushNamed('/Todos');
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Text('More'),
|
||||
Icon(Icons.keyboard_arrow_right)
|
||||
],
|
||||
),
|
||||
|
||||
LoadStats();
|
||||
},
|
||||
child: Text((taskTypeRange != null) ? (DateFormat("MM/dd").format(taskTypeRange!.start) + " - " + DateFormat("MM/dd").format(taskTypeRange!.end)) : 'n/a'),
|
||||
)
|
||||
]),
|
||||
Expanded(
|
||||
// maxHeight: 300,
|
||||
// maxWidth: 100,
|
||||
child: SfCartesianChart(primaryXAxis: CategoryAxis(),
|
||||
//primaryYAxis: NumericAxis(minimum: 0, maximum: 40, interval: 10),
|
||||
series: <ChartSeries<TaskTypeMapData, String>>[
|
||||
BarSeries<TaskTypeMapData, String>(
|
||||
dataSource: taskTypesData,
|
||||
xValueMapper: (TaskTypeMapData data, _) => data.task,
|
||||
yValueMapper: (TaskTypeMapData data, _) => data.time / 60,
|
||||
pointColorMapper: (TaskTypeMapData data, _) => data.color,
|
||||
dataLabelMapper: (TaskTypeMapData data, _) => MinutesToTimeString(data.time),
|
||||
dataLabelSettings: DataLabelSettings(isVisible: true),
|
||||
color: Color.fromRGBO(8, 142, 255, 1))
|
||||
]),
|
||||
)
|
||||
])))),
|
||||
Container(
|
||||
height: (catsData.length * 45).clamp(350, 1000).toDouble(),
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Card(
|
||||
color: Colors.white10,
|
||||
elevation: 20,
|
||||
shadowColor: Colors.black,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 25),
|
||||
child: Column(children: [
|
||||
Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||
Text("Categories", style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
DateTimeRange? value = await showDateRangePicker(context: context, firstDate: firstDay ?? DateTime.now(), lastDate: lastDay ?? DateTime.now());
|
||||
if (value != null) {
|
||||
catsRange = value;
|
||||
}
|
||||
)
|
||||
],
|
||||
),
|
||||
LimitedBox(
|
||||
maxHeight: 250,
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: relativeTodos.length,
|
||||
itemBuilder: (context, index){
|
||||
return Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
margin: EdgeInsets.symmetric(vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black26,
|
||||
borderRadius: BorderRadius.circular(10)
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
SizedBox(width:MediaQuery.of(context).size.width * 0.7,child: Text('${relativeTodos[index].task!.name} -> ${relativeTodos[index].metadata}')),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 5),
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(20), color: Colors.blue),
|
||||
child: Text(DateFormat('MM/dd').format(relativeTodos[index].dueDate))
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Card(
|
||||
color: Colors.white10,
|
||||
elevation: 20,
|
||||
shadowColor: Colors.black,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 20),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Container(width:100,height: 150,child: CustomPaint(painter: HourglassPainter(hourglassTime, hourglassColors, hourglassStops),)),
|
||||
Column(
|
||||
children: [
|
||||
Text(DateFormat("MMMM-dd").format(DateTime.now()),style:TextStyle(fontSize: 18)),
|
||||
Text(DateFormat("hh:mm a").format(DateTime.now()),style:TextStyle(fontSize: 40, fontWeight: FontWeight.bold)),
|
||||
Container(height: 20,)
|
||||
],
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
Container(
|
||||
height: 400,
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Card(
|
||||
color: Colors.white10,
|
||||
elevation: 20,
|
||||
shadowColor: Colors.black,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10,vertical: 0),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text("Productivity", style: TextStyle(color: Colors.green, fontWeight: FontWeight.bold)),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
DateTimeRange? value = await showDateRangePicker(context: context, firstDate: firstDay ?? DateTime.now(), lastDate: lastDay ?? DateTime.now());
|
||||
if (value != null) {
|
||||
prodRange = DateTimeRange(start: DateTime(value.start.year, value.start.month, value.start.day), end: DateTime(value.end.year,value.end.month,value.end.day,23,59,59));
|
||||
}
|
||||
|
||||
LoadStats();
|
||||
},
|
||||
child: Text((catsRange != null) ? (DateFormat("MM/dd").format(catsRange!.start) + " - " + DateFormat("MM/dd").format(catsRange!.end)) : 'n/a'),
|
||||
)
|
||||
]),
|
||||
Expanded(
|
||||
// maxHeight: 300,
|
||||
// maxWidth: 100,
|
||||
child: SfCartesianChart(primaryXAxis: CategoryAxis(),
|
||||
//primaryYAxis: NumericAxis(minimum: 0, maximum: 40, interval: 10),
|
||||
series: <ChartSeries<CatMapData, String>>[
|
||||
BarSeries<CatMapData, String>(
|
||||
dataSource: catsData,
|
||||
xValueMapper: (CatMapData data, _) => data.name,
|
||||
yValueMapper: (CatMapData data, _) => data.time / 60,
|
||||
pointColorMapper: (CatMapData data, _) => data.color,
|
||||
dataLabelMapper: (CatMapData data, _) => MinutesToTimeString(data.time),
|
||||
dataLabelSettings: DataLabelSettings(isVisible: true),
|
||||
color: Color.fromRGBO(8, 142, 255, 1))
|
||||
LoadStats();
|
||||
},
|
||||
child: Text((prodRange != null) ? (DateFormat("MM/dd").format(prodRange!.start) + " - " + DateFormat("MM/dd").format(prodRange!.end)) : 'n/a'),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Divider(),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text("Today : "),
|
||||
Text("${(productivityData.length > 0) ? productivityData[0].productivity.toStringAsFixed(1) : 'n/a'}%",
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: (productivityData.length > 1)
|
||||
? ((productivityData[0].productivity > productivityData[1].productivity) ? Colors.lightGreenAccent : Colors.red)
|
||||
: Colors.white))
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text("Yesterday : "),
|
||||
Text("${(productivityData.length > 1) ? productivityData[1].productivity.toStringAsFixed(1) : 'n/a'}%", style: TextStyle(fontSize: 18))
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: SfCartesianChart(
|
||||
// Initialize category axis
|
||||
primaryXAxis: CategoryAxis(),
|
||||
series: <LineSeries<ProductivityMapData, String>>[
|
||||
LineSeries<ProductivityMapData, String>(
|
||||
// Bind data source
|
||||
markerSettings: MarkerSettings(isVisible: true, shape: DataMarkerType.circle),
|
||||
dataSource: productivityData.reversed.toList(),
|
||||
xValueMapper: (ProductivityMapData sales, _) => DateFormat('MM-dd').format(dFormat.parse(sales.day)),
|
||||
yValueMapper: (ProductivityMapData sales, _) => sales.productivity,
|
||||
dataLabelMapper: (ProductivityMapData sales, _) => sales.productivity.toStringAsFixed(1) + "%",
|
||||
dataLabelSettings: DataLabelSettings(overflowMode: OverflowMode.hide, showZeroValue: false, isVisible: true),
|
||||
onPointTap: (ChartPointDetails point){
|
||||
Dialogs.showJournalLink(dFormat.parse(productivityData[productivityData.length-point.pointIndex!-1].day));
|
||||
//showAlertDialog(context, productivityData[point.pointIndex!].day, "I'll show you detailed info about this day in future, When my master creates the feature");
|
||||
},
|
||||
pointColorMapper: (ProductivityMapData sales, _)=> (User.journalExists(dFormat.parse(sales.day)) ? Colors.lightGreenAccent : Colors.green)
|
||||
),
|
||||
LineSeries<ProductivityMapData, String>(
|
||||
// Bind data source
|
||||
// dashArray: [0,0.5,1],
|
||||
dashArray: [2,5],
|
||||
markerSettings: MarkerSettings(isVisible: true, shape: DataMarkerType.circle),
|
||||
dataSource: pastProductivityData.reversed.toList(),
|
||||
xValueMapper: (ProductivityMapData sales, _) => DateFormat('MM-dd').format(dFormat.parse(sales.day)),
|
||||
yValueMapper: (ProductivityMapData sales, _) => sales.productivity,
|
||||
// dataLabelMapper: (ProductivityMapData sales, _) => sales.productivity.toStringAsFixed(1) + "%",
|
||||
// dataLabelSettings: DataLabelSettings(overflowMode: OverflowMode.hide, showZeroValue: false, isVisible: true),
|
||||
|
||||
color: Colors.grey
|
||||
// pointColorMapper: (ProductivityMapData sales, _)=> (User.journalExists(dFormat.parse(sales.day)) ? Colors.lightGreenAccent : Colors.green)
|
||||
)
|
||||
//color: User.journalExists(dFormat.parse(productivityData[(productivityData.length-point.pointIndex!-1) as int].day)) ?Colors.green : Colors.red,
|
||||
]),
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text("Average : "),
|
||||
Text("${(productivityData.length > 0) ? avgProd.toStringAsFixed(1) : 'n/a'}%",
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: (avgProd > pastAvgProd) ? Colors.lightGreenAccent : Colors.red))
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text("Past Average : "),
|
||||
Text("${(productivityData.length > 1) ? pastAvgProd.toStringAsFixed(1) : 'n/a'}%", style: TextStyle(fontSize: 18))
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20,),
|
||||
if(lastProductive!=null && DateTime.now().difference(lastProductive!).inMinutes > 60)RichText(text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(text: "You haven't been productive in last",style: TextStyle(color:Colors.orange)),
|
||||
TextSpan(text:" ${MinutesToTimeString(DateTime.now().difference(lastProductive!).inMinutes)}",style: TextStyle(color:Colors.redAccent,fontWeight: FontWeight.bold))
|
||||
]
|
||||
))
|
||||
|
||||
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
Container(
|
||||
height: 400,
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Card(
|
||||
color: Colors.white10,
|
||||
elevation: 20,
|
||||
shadowColor: Colors.black,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: (!days.isEmpty)
|
||||
? Column(
|
||||
children: [
|
||||
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||
Padding(padding: EdgeInsets.all(20), child: Text('Daily Briefing', style: TextStyle(fontWeight: FontWeight.bold))),
|
||||
dayPickerWidget(days, value: curDay, onChange: (_value) {
|
||||
print('new val : $_value');
|
||||
curDay = _value;
|
||||
setState(() {
|
||||
LoadStats();
|
||||
});
|
||||
}),
|
||||
]),
|
||||
Expanded(
|
||||
child: SfCircularChart(legend: Legend(isVisible: true,position: LegendPosition.bottom,overflowMode: LegendItemOverflowMode.wrap), series: <CircularSeries>[
|
||||
// Render pie chart
|
||||
PieSeries<CatMapData, String>(
|
||||
dataSource: dailyData,
|
||||
pointColorMapper: (CatMapData data, _) => data.color,
|
||||
xValueMapper: (CatMapData data, _) => data.name,
|
||||
yValueMapper: (CatMapData data, _) => data.time,
|
||||
dataLabelMapper: (CatMapData sales, _) => MinutesToTimeString(sales.time),
|
||||
dataLabelSettings: DataLabelSettings(isVisible: true, useSeriesColor: true, overflowMode: OverflowMode.shift, showZeroValue: false))
|
||||
]))
|
||||
],
|
||||
)
|
||||
: Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: [CircularProgressIndicator()])))),
|
||||
Container(
|
||||
height: (taskTypesData.length * 45).clamp(350, 1000).toDouble(),
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Card(
|
||||
color: Colors.white10,
|
||||
elevation: 20,
|
||||
shadowColor: Colors.black,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 25),
|
||||
child: Column(children: [
|
||||
Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||
Text("Task Types", style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
DateTimeRange? value = await showDateRangePicker(context: context, firstDate: firstDay ?? DateTime.now(), lastDate: lastDay ?? DateTime.now());
|
||||
if (value != null) {
|
||||
taskTypeRange = value;
|
||||
}
|
||||
|
||||
LoadStats();
|
||||
},
|
||||
child: Text((taskTypeRange != null) ? (DateFormat("MM/dd").format(taskTypeRange!.start) + " - " + DateFormat("MM/dd").format(taskTypeRange!.end)) : 'n/a'),
|
||||
)
|
||||
]),
|
||||
)
|
||||
])))),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
// maxHeight: 300,
|
||||
// maxWidth: 100,
|
||||
child: SfCartesianChart(primaryXAxis: CategoryAxis(),
|
||||
//primaryYAxis: NumericAxis(minimum: 0, maximum: 40, interval: 10),
|
||||
series: <ChartSeries<TaskTypeMapData, String>>[
|
||||
BarSeries<TaskTypeMapData, String>(
|
||||
dataSource: taskTypesData,
|
||||
xValueMapper: (TaskTypeMapData data, _) => data.task,
|
||||
yValueMapper: (TaskTypeMapData data, _) => data.time / 60,
|
||||
pointColorMapper: (TaskTypeMapData data, _) => data.color,
|
||||
dataLabelMapper: (TaskTypeMapData data, _) => MinutesToTimeString(data.time),
|
||||
dataLabelSettings: DataLabelSettings(isVisible: true),
|
||||
color: Color.fromRGBO(8, 142, 255, 1))
|
||||
]),
|
||||
)
|
||||
])))),
|
||||
Container(
|
||||
height: (catsData.length * 45).clamp(350, 1000).toDouble(),
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Card(
|
||||
color: Colors.white10,
|
||||
elevation: 20,
|
||||
shadowColor: Colors.black,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 25),
|
||||
child: Column(children: [
|
||||
Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||
Text("Categories", style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
DateTimeRange? value = await showDateRangePicker(context: context, firstDate: firstDay ?? DateTime.now(), lastDate: lastDay ?? DateTime.now());
|
||||
if (value != null) {
|
||||
catsRange = value;
|
||||
}
|
||||
|
||||
LoadStats();
|
||||
},
|
||||
child: Text((catsRange != null) ? (DateFormat("MM/dd").format(catsRange!.start) + " - " + DateFormat("MM/dd").format(catsRange!.end)) : 'n/a'),
|
||||
)
|
||||
]),
|
||||
Expanded(
|
||||
// maxHeight: 300,
|
||||
// maxWidth: 100,
|
||||
child: SfCartesianChart(primaryXAxis: CategoryAxis(),
|
||||
//primaryYAxis: NumericAxis(minimum: 0, maximum: 40, interval: 10),
|
||||
series: <ChartSeries<CatMapData, String>>[
|
||||
BarSeries<CatMapData, String>(
|
||||
dataSource: catsData,
|
||||
xValueMapper: (CatMapData data, _) => data.name,
|
||||
yValueMapper: (CatMapData data, _) => data.time / 60,
|
||||
pointColorMapper: (CatMapData data, _) => data.color,
|
||||
dataLabelMapper: (CatMapData data, _) => MinutesToTimeString(data.time),
|
||||
dataLabelSettings: DataLabelSettings(isVisible: true),
|
||||
color: Color.fromRGBO(8, 142, 255, 1))
|
||||
]),
|
||||
)
|
||||
])))),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user