Project Steps completion
This commit is contained in:
@@ -1,232 +1,412 @@
|
||||
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/NewProject.dart';
|
||||
import 'package:tasktracker/Projects.dart';
|
||||
import 'User.dart' as User;
|
||||
import 'Dialogs.dart';
|
||||
|
||||
import 'Data.dart';
|
||||
import 'main.dart';
|
||||
|
||||
class ProjectDetails extends StatefulWidget {
|
||||
ProjectDetails({Key? key, required this.project}) : super(key: key);
|
||||
ProjectDetails({Key? key, required this.project}) : super(key: key);
|
||||
Project project;
|
||||
@override
|
||||
State<ProjectDetails> createState() => _ProjectDetailsState(project);
|
||||
}
|
||||
|
||||
DateTime justDate(DateTime dateTime){
|
||||
DateTime justDate(DateTime dateTime) {
|
||||
return DateTime(dateTime.year, dateTime.month, dateTime.day);
|
||||
}
|
||||
|
||||
class _ProjectDetailsState extends State<ProjectDetails> {
|
||||
|
||||
_ProjectDetailsState(this.project);
|
||||
Project project ;
|
||||
Project project;
|
||||
int etaHours = 0;
|
||||
List<ProjectChartData> chartData = [];
|
||||
|
||||
int totalTimeSpent = 0;
|
||||
List<ProjectChartData> timeSpentData = [];
|
||||
List<ProjectChartData> timeProgressionData = [];
|
||||
|
||||
String chartOption = 'Time Spent';
|
||||
DateTimeRange? chartRange;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
List<Widget> stepsWidgets = printSteps();
|
||||
etaHours =0;
|
||||
etaHours = (project.steps.length > 0) ? 0 : project.eta ?? 0;
|
||||
totalTimeSpent = 0;
|
||||
project.steps.forEach((element) {
|
||||
etaHours+=element.eta;
|
||||
etaHours += element.eta;
|
||||
});
|
||||
int lastIndex = -1;
|
||||
int lastDay = -1;
|
||||
User.activities.forEach((element) {
|
||||
if(element.taskType.relatedProject == project){
|
||||
if(lastDay != element.startTime.day){
|
||||
chartData.add(ProjectChartData(justDate(element.startTime), element.endTime.difference(element.startTime).inMinutes));
|
||||
lastIndex++;
|
||||
lastDay = element.startTime.day;
|
||||
}else{
|
||||
chartData[lastIndex].timeSpent += element.endTime.difference(element.startTime).inMinutes;
|
||||
timeSpentData = [];
|
||||
timeProgressionData = [];
|
||||
DateTime? firstDateTime = null;
|
||||
DateTime? lastDateTime = null;
|
||||
User.activities.reversed.forEach((element) {
|
||||
|
||||
bool withinRange =
|
||||
(chartRange == null) || (chartRange != null && chartRange!.start.isBefore(element.startTime) && chartRange!.end.isAfter(element.endTime));
|
||||
if (element.taskType.relatedProject != null && element.taskType.relatedProject!.name == project.name) {
|
||||
print('here');
|
||||
if (withinRange) {
|
||||
if (firstDateTime == null) {
|
||||
firstDateTime = element.startTime;
|
||||
}
|
||||
lastDateTime = element.startTime;
|
||||
|
||||
if (lastDay != element.startTime.day) {
|
||||
if (totalTimeSpent > 0) {
|
||||
timeProgressionData.add(ProjectChartData(justDate(element.startTime), totalTimeSpent));
|
||||
}
|
||||
timeSpentData.add(ProjectChartData(justDate(element.startTime), element.endTime.difference(element.startTime).inMinutes));
|
||||
lastIndex++;
|
||||
lastDay = element.startTime.day;
|
||||
print('new day : $lastDay');
|
||||
} else {
|
||||
timeSpentData[lastIndex].timeSpent += element.endTime.difference(element.startTime).inMinutes;
|
||||
}
|
||||
|
||||
}
|
||||
totalTimeSpent += element.endTime.difference(element.startTime).inMinutes;
|
||||
}
|
||||
});
|
||||
chartRange ??= (lastDateTime != null && firstDateTime != null) ? DateTimeRange(end: lastDateTime!, start: firstDateTime!) : null;
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Row(
|
||||
appBar: AppBar(
|
||||
title: Row(
|
||||
children: [
|
||||
FaIcon(FontAwesomeIcons.projectDiagram),
|
||||
SizedBox(width: 15,),
|
||||
SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
Text(project.name),
|
||||
],
|
||||
)),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Card(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Card(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
DropdownButton<String>(
|
||||
value: chartOption,
|
||||
icon: const Icon(Icons.arrow_downward),
|
||||
elevation: 16,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
underline: Container(
|
||||
height: 2,
|
||||
color: Colors.deepPurpleAccent,
|
||||
),
|
||||
onChanged: (String? newValue) {
|
||||
setState(() {
|
||||
chartOption = newValue!;
|
||||
});
|
||||
},
|
||||
items: <String>['Time Spent', 'Time Progression', 'Steps Progression', 'Time & Steps Progression']
|
||||
.map<DropdownMenuItem<String>>((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(value),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
FaIcon(FontAwesomeIcons.calendar),
|
||||
SizedBox(
|
||||
width: 8,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
DateTimeRange? value = await showDateRangePicker(
|
||||
context: context, firstDate: firstDay ?? DateTime.now(), lastDate: lastDateTime ?? DateTime.now());
|
||||
if (value != null) {
|
||||
chartRange = value;
|
||||
}
|
||||
|
||||
),
|
||||
Card(child: Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: Column(
|
||||
children: [
|
||||
Text("Time Management"),
|
||||
SizedBox(height: 10,),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(flex:1,child: Text('ETA :',textAlign: TextAlign.end,)),
|
||||
Expanded(flex: 3,child: Text( '${etaHours} Hours',textAlign: TextAlign.center,),)
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(flex:1,child: Text('Deadline :',textAlign: TextAlign.end,)),
|
||||
Expanded(flex: 3,child: Text( '${DateFormat('yyyy-MM-dd').format(project.deadline)}',textAlign: TextAlign.center,),)
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(flex:1,child: Text('Remaining :',textAlign: TextAlign.end,)),
|
||||
Expanded(flex: 3,child: Text( '${durationToDays(project.deadline.difference(DateTime.now()))}',textAlign: TextAlign.center,),)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
],
|
||||
),
|
||||
)),
|
||||
Card(child:Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Text('Steps',),
|
||||
LimitedBox(
|
||||
maxHeight: 300,
|
||||
child: Container(
|
||||
|
||||
padding: EdgeInsets.all(10),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: (stepsWidgets.isNotEmpty) ? Container(
|
||||
child: Column(
|
||||
children: stepsWidgets,
|
||||
setState(() {});
|
||||
},
|
||||
child: Text((chartRange != null)
|
||||
? (DateFormat("MM/dd").format(chartRange!.start) + " - " + DateFormat("MM/dd").format(chartRange!.end))
|
||||
: 'n/a'),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
) : Container(
|
||||
|
||||
height: 20,
|
||||
child: Text('Click on + to add steps')
|
||||
)),
|
||||
),
|
||||
SfCartesianChart(
|
||||
// Initialize category axis
|
||||
primaryXAxis: CategoryAxis(),
|
||||
series: <LineSeries<ProjectChartData, String>>[
|
||||
if (chartOption == 'Time Spent')
|
||||
LineSeries<ProjectChartData, String>(
|
||||
// Bind data source
|
||||
dataSource: timeSpentData,
|
||||
xValueMapper: (ProjectChartData sales, _) => DateFormat("MM/dd").format(sales.day),
|
||||
yValueMapper: (ProjectChartData sales, _) => sales.timeSpent / 60,
|
||||
dataLabelMapper: (ProjectChartData sales, _) => MinutesToTimeString(sales.timeSpent),
|
||||
dataLabelSettings: DataLabelSettings(overflowMode: OverflowMode.hide, showZeroValue: false, isVisible: true),
|
||||
onPointTap: (ChartPointDetails point) {
|
||||
showAlertDialog(context, DateFormat("MM/dd").format(timeSpentData[point.pointIndex!].day),
|
||||
"I'll show you detailed info about this day in future, When my master creates the feature");
|
||||
},
|
||||
color: Colors.blue),
|
||||
if (chartOption == 'Time Progression')
|
||||
LineSeries<ProjectChartData, String>(
|
||||
// Bind data source
|
||||
dataSource: timeProgressionData,
|
||||
xValueMapper: (ProjectChartData sales, _) => DateFormat("MM/dd").format(sales.day),
|
||||
yValueMapper: (ProjectChartData sales, _) => sales.timeSpent / 60,
|
||||
dataLabelMapper: (ProjectChartData sales, _) => MinutesToTimeString(sales.timeSpent),
|
||||
dataLabelSettings: DataLabelSettings(overflowMode: OverflowMode.hide, showZeroValue: false, isVisible: true),
|
||||
onPointTap: (ChartPointDetails point) {
|
||||
showAlertDialog(context, DateFormat("MM/dd").format(timeSpentData[point.pointIndex!].day),
|
||||
"I'll show you detailed info about this day in future, When my master creates the feature");
|
||||
},
|
||||
color: Colors.blue)
|
||||
]),
|
||||
],
|
||||
))),
|
||||
Card(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: Column(
|
||||
children: [
|
||||
Text("Time Management"),
|
||||
SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 40,vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: Colors.black26,
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
'ETA :',
|
||||
textAlign: TextAlign.end,
|
||||
)),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(
|
||||
(etaHours > 0) ? '${etaHours} Hours' : 'You have no idea',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
'Time Spent :',
|
||||
textAlign: TextAlign.end,
|
||||
)),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(
|
||||
(totalTimeSpent > 0) ? MinutesToTimeString(totalTimeSpent) : 'Not a single minute',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
'Deadline :',
|
||||
textAlign: TextAlign.end,
|
||||
)),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(
|
||||
'${DateFormat('yyyy-MM-dd').format(project.deadline)}',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
'Remaining :',
|
||||
textAlign: TextAlign.end,
|
||||
)),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(
|
||||
'${durationToDays(project.deadline.difference(DateTime.now()))}',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
if (project.steps.length > 0)
|
||||
Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Text("Total time : $etaHours Hours"),
|
||||
Text(
|
||||
'Steps',
|
||||
),
|
||||
LimitedBox(
|
||||
maxHeight: 300,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: (stepsWidgets.isNotEmpty)
|
||||
? Container(
|
||||
child: Column(
|
||||
children: stepsWidgets,
|
||||
),
|
||||
)
|
||||
: Container(height: 20, child: Text('Click on + to add steps'))),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 40, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: Colors.black26,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Text("Total time : $etaHours Hours"),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),),
|
||||
|
||||
Card(child:Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Text('Actions'),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
ElevatedButton(onPressed: (){}, child: Row(
|
||||
children: [
|
||||
FaIcon(FontAwesomeIcons.edit),
|
||||
SizedBox(width: 10,),
|
||||
Text('Edit'),
|
||||
],
|
||||
)),
|
||||
ElevatedButton(style:ElevatedButton.styleFrom(
|
||||
primary: Colors.red,
|
||||
),onPressed: (){}, child: Row(
|
||||
children: [
|
||||
FaIcon(FontAwesomeIcons.deleteLeft),
|
||||
SizedBox(width: 10,),
|
||||
Text('Delete'),
|
||||
],
|
||||
))
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Text('Actions'),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () {},
|
||||
child: Row(
|
||||
children: [
|
||||
FaIcon(FontAwesomeIcons.edit),
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Text('Edit'),
|
||||
],
|
||||
)),
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
primary: Colors.red,
|
||||
),
|
||||
onPressed: () {},
|
||||
child: Row(
|
||||
children: [
|
||||
FaIcon(FontAwesomeIcons.deleteLeft),
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Text('Delete'),
|
||||
],
|
||||
))
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
) ,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> printSteps() {
|
||||
List<Widget> _steps = [];
|
||||
|
||||
Widget title=Container(
|
||||
|
||||
height: 30,
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(20), color: Colors.white10),
|
||||
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(flex: 4, child: Text('Name')),
|
||||
// Expanded(flex:1,child: Icon(Icons.timelapse)),
|
||||
Expanded(flex: 2, child: Text("Progress")),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text('ETA',textAlign: TextAlign.end,))
|
||||
],
|
||||
));
|
||||
|
||||
//Checkbox(value: false, onChanged: null),
|
||||
// _steps.add(title);
|
||||
// _steps.add(Divider());
|
||||
for (int i = 0; i < project.steps.length; i++) {
|
||||
ProjectStep value = project.steps[i];
|
||||
_steps.add(InkWell(
|
||||
child: Container(
|
||||
height: 30,
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), color:Colors.black26),
|
||||
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(flex: 4, child: Text(value.stepName)),
|
||||
// Expanded(flex:1,child: Icon(Icons.timelapse)),
|
||||
Expanded(flex: 1, child: Text("${value.progress}%")),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(
|
||||
value.eta.toString() + " Hours",
|
||||
textAlign: TextAlign.end,
|
||||
))
|
||||
],
|
||||
))));
|
||||
_steps.add(Row(
|
||||
children: [
|
||||
InkWell(onTap: (){
|
||||
Dialogs.completeStepDialog(project,(date) {
|
||||
User.UserOperations.CompleteProjectStep(project, project.steps[i], date);
|
||||
}, project.steps[i]);
|
||||
},child: Container(margin:EdgeInsets.all(2),child: Icon((project.steps[i].finishedDate!= null) ?Icons.check_box : Icons.check_box_outline_blank))),
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 34,
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), color: Colors.black26),
|
||||
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(flex: 4, child: Text(value.stepName)),
|
||||
// Expanded(flex:1,child: Icon(Icons.timelapse)),
|
||||
Expanded(flex: 1, child: Text("${value.progress}%")),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(
|
||||
value.eta.toString() + " Hours",
|
||||
textAlign: TextAlign.end,
|
||||
))
|
||||
],
|
||||
)),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
return _steps;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ProjectChartData{
|
||||
|
||||
class ProjectChartData {
|
||||
ProjectChartData(this.day, this.timeSpent);
|
||||
|
||||
DateTime day;
|
||||
int timeSpent;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user