Somethings, idk what I made

This commit is contained in:
Sewmina
2022-04-21 15:56:23 +05:30
parent 1f35254b5b
commit fd9cef8687
5 changed files with 549 additions and 385 deletions

View File

@@ -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;

View File

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

View File

@@ -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)) {

View File

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

View File

@@ -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))
]),
)
])))),
],
),
),
),
],
),
),
],