Summary page done
|
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 442 B After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 721 B After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 19 KiB |
BIN
images/hourglass_base.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
images/hourglass_half.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'main.dart';
|
import 'main.dart';
|
||||||
@@ -6,15 +7,15 @@ import 'Data.dart';
|
|||||||
import 'User.dart' as User;
|
import 'User.dart' as User;
|
||||||
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
|
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Activities extends StatefulWidget {
|
class Activities extends StatefulWidget {
|
||||||
const Activities({Key? key}) : super(key: key);
|
const Activities({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_ActivitiesState createState() => _ActivitiesState();
|
_ActivitiesState createState() => _ActivitiesState();
|
||||||
}
|
}
|
||||||
|
|
||||||
late ProgressDialog progressDialog;
|
late ProgressDialog progressDialog;
|
||||||
|
|
||||||
class _ActivitiesState extends State<Activities> {
|
class _ActivitiesState extends State<Activities> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -26,9 +27,8 @@ class _ActivitiesState extends State<Activities> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
progressDialog=ProgressDialog(context: context);
|
progressDialog = ProgressDialog(context: context);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
|
||||||
floatingActionButton: FloatingActionButton.extended(
|
floatingActionButton: FloatingActionButton.extended(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context)
|
Navigator.of(context)
|
||||||
@@ -39,7 +39,7 @@ class _ActivitiesState extends State<Activities> {
|
|||||||
icon: Icon(Icons.add)),
|
icon: Icon(Icons.add)),
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Row(
|
title: Row(
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Row(children: [
|
Row(children: [
|
||||||
@@ -47,15 +47,29 @@ class _ActivitiesState extends State<Activities> {
|
|||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
Text('Activities')
|
Text('Activities')
|
||||||
]),
|
]),
|
||||||
(selecting)?Row(children: [
|
(selecting)
|
||||||
InkWell(onTap: (){
|
? Row(children: [
|
||||||
DeleteSelectedTasks();
|
InkWell(
|
||||||
}, child: Icon(Icons.delete,size: 30,)),
|
onTap: () {
|
||||||
SizedBox(width: 20,),
|
DeleteSelectedTasks();
|
||||||
InkWell(onTap: (){setState(() {
|
},
|
||||||
selecting=false;
|
child: Icon(
|
||||||
});}, child: Icon(Icons.close,size: 30),)
|
Icons.delete,
|
||||||
]) : Container(),
|
size: 30,
|
||||||
|
)),
|
||||||
|
SizedBox(
|
||||||
|
width: 20,
|
||||||
|
),
|
||||||
|
InkWell(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
selecting = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Icon(Icons.close, size: 30),
|
||||||
|
)
|
||||||
|
])
|
||||||
|
: Container(),
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
drawer: navDrawer(context, 2),
|
drawer: navDrawer(context, 2),
|
||||||
@@ -68,10 +82,14 @@ class _ActivitiesState extends State<Activities> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UpdateList() async {
|
void UpdateList() async {
|
||||||
try{progressDialog.show(max:100,msg: 'Loading Activities');}catch(e){}
|
try {
|
||||||
|
progressDialog.show(max: 100, msg: 'Loading Activities');
|
||||||
|
} catch (e) {}
|
||||||
await User.updateActList();
|
await User.updateActList();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
try{progressDialog.update(value: 100);}catch(e){}
|
try {
|
||||||
|
progressDialog.update(value: 100);
|
||||||
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> PrintTasks() {
|
List<Widget> PrintTasks() {
|
||||||
@@ -79,19 +97,52 @@ class _ActivitiesState extends State<Activities> {
|
|||||||
print('Priting cats : ' + User.taskTypes.length.toString());
|
print('Priting cats : ' + User.taskTypes.length.toString());
|
||||||
String lastDate = "";
|
String lastDate = "";
|
||||||
DateFormat dFormat = DateFormat("MM/dd");
|
DateFormat dFormat = DateFormat("MM/dd");
|
||||||
|
Map<String, int> productivtyActs = <String, int>{};
|
||||||
|
Map<String, int> unproductivtyActs = <String, int>{};
|
||||||
|
Map<String, int> totalMinutes = <String, int>{};
|
||||||
for (var element in User.activities) {
|
for (var element in User.activities) {
|
||||||
String thisDate = dFormat.format(element.startTime);
|
String thisDate = dFormat.format(element.startTime);
|
||||||
if(thisDate != lastDate){
|
int thisMinutes= element.endTime.difference(element.startTime).inMinutes;
|
||||||
_tasks.add(DateSeperator(thisDate));
|
if(totalMinutes.containsKey(thisDate)){
|
||||||
lastDate=thisDate;
|
if((totalMinutes[thisDate]??0) < thisMinutes){
|
||||||
|
totalMinutes[thisDate] = thisMinutes;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
totalMinutes.putIfAbsent(thisDate, () => thisMinutes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.taskType.cat?.productive ?? false) {
|
||||||
|
if (productivtyActs.containsKey(thisDate)) {
|
||||||
|
productivtyActs[thisDate] = (productivtyActs[thisDate]! + thisMinutes);
|
||||||
|
} else {
|
||||||
|
productivtyActs.putIfAbsent(thisDate, () => thisMinutes);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (unproductivtyActs.containsKey(thisDate)) {
|
||||||
|
unproductivtyActs[thisDate] = (unproductivtyActs[thisDate]! + thisMinutes);
|
||||||
|
} else {
|
||||||
|
unproductivtyActs.putIfAbsent(thisDate, () => thisMinutes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print(productivtyActs);
|
||||||
|
for (var element in User.activities) {
|
||||||
|
String thisDate = dFormat.format(element.startTime);
|
||||||
|
if (thisDate != lastDate) {
|
||||||
|
int prodActs = productivtyActs[thisDate] ?? 0;
|
||||||
|
int unProdActs = unproductivtyActs[thisDate] ?? 0;
|
||||||
|
_tasks.add(DateSeperator(thisDate, prodActs, unProdActs));
|
||||||
|
lastDate = thisDate;
|
||||||
}
|
}
|
||||||
String name = element.taskType.name;
|
String name = element.taskType.name;
|
||||||
if (element.taskType.cat == null) {
|
if (element.taskType.cat == null) {
|
||||||
print('Got some null cat : ${element.taskType.name}');
|
print('Got some null cat : ${element.taskType.name}');
|
||||||
} else {
|
} else {
|
||||||
Color color = HexColor.fromHex(element.taskType.cat?.color ?? '#000000');
|
Color color =
|
||||||
|
HexColor.fromHex(element.taskType.cat?.color ?? '#000000');
|
||||||
bool productive = element.taskType.cat?.productive ?? true;
|
bool productive = element.taskType.cat?.productive ?? true;
|
||||||
Widget task = ActivityCard(context, name,element.startTime,element.endTime, productive, color,element);
|
Widget task = ActivityCard(context, name, element.startTime,
|
||||||
|
element.endTime, productive, color, element, totalMinutes[thisDate] ?? 0);
|
||||||
_tasks.add(task);
|
_tasks.add(task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,23 +150,65 @@ class _ActivitiesState extends State<Activities> {
|
|||||||
return _tasks;
|
return _tasks;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget DateSeperator(date){
|
Widget DateSeperator(date, prodActs, unprodActs) {
|
||||||
|
double prodPercentage = (prodActs / (prodActs + unprodActs)) * 100;
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(10, 20, 10, 0),
|
padding: const EdgeInsets.fromLTRB(10, 20, 10, 0),
|
||||||
child: Column(children: [
|
child: Column(
|
||||||
Row(children: [
|
children: [
|
||||||
Text(date,style: TextStyle(fontSize: 18),)
|
Row(
|
||||||
],)
|
mainAxisSize: MainAxisSize.max,
|
||||||
],),
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
date,
|
||||||
|
style: TextStyle(fontSize: 18),
|
||||||
|
),
|
||||||
|
Row(children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Container(child:Align(child:Text(MinutesToTimeString(prodActs)), alignment: Alignment.center,),width: (prodPercentage) * 1.7, height: 25,decoration: BoxDecoration(color: Colors.green,borderRadius: BorderRadius.horizontal(left: Radius.circular(10))),),
|
||||||
|
Container(child:Align(child:Text(MinutesToTimeString(unprodActs)), alignment: Alignment.center,),width: (100-prodPercentage)* 1.7,height: 25,decoration: BoxDecoration(color: Colors.red,borderRadius: BorderRadius.horizontal(right: Radius.circular(10))),),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(width: 10,),
|
||||||
|
Text(prodPercentage.toStringAsFixed(1) + "%",style: TextStyle(color: Colors.green, fontWeight: FontWeight.bold,fontSize: 20))
|
||||||
|
],)
|
||||||
|
// CustomPaint(
|
||||||
|
// painter: MyPlayerBar(100, prodPercentage.toInt(),
|
||||||
|
// background: Colors.green, fill: Colors.deepOrange),
|
||||||
|
// child: Container(
|
||||||
|
// alignment: Alignment.center,
|
||||||
|
// height: 25.0,
|
||||||
|
// width: 200,
|
||||||
|
// child: Text(
|
||||||
|
// "Productivity : ${prodPercentage.toStringAsFixed(1)}%",
|
||||||
|
// style: TextStyle(fontWeight: FontWeight.bold),),
|
||||||
|
//
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool selecting = false;
|
bool selecting = false;
|
||||||
Widget ActivityCard(
|
Widget ActivityCard(BuildContext context, String name, DateTime sTime,
|
||||||
BuildContext context, String name,DateTime sTime, DateTime eTime, bool productive, Color color, Activity activity) {
|
DateTime eTime, bool productive, Color color, Activity activity,int totalMinutes) {
|
||||||
DateFormat dateFormat = DateFormat("HH:mm");
|
DateFormat dateFormat = DateFormat("HH:mm");
|
||||||
|
int thisMinutes = (activity.endTime.difference(activity.startTime).inMinutes);
|
||||||
|
int timePercentage = ((thisMinutes / totalMinutes) * 100).toInt();
|
||||||
|
// print("$thisMinutes / $totalMinutes");
|
||||||
|
bool containsMetadata = ((activity.metadata ?? 'null') != 'null') &&
|
||||||
|
((activity.metadata ?? '').isNotEmpty);
|
||||||
var _timeSpan = eTime.difference(sTime);
|
var _timeSpan = eTime.difference(sTime);
|
||||||
String timeSpan = ((_timeSpan.inHours > 0) ? _timeSpan.inHours.toString()+'h ' : '') + ((_timeSpan.inMinutes %60 > 0) ? (_timeSpan.inMinutes%60).toString()+'m ' : '');
|
String timeSpan =
|
||||||
|
((_timeSpan.inHours > 0) ? _timeSpan.inHours.toString() + 'h ' : '') +
|
||||||
|
((_timeSpan.inMinutes % 60 > 0)
|
||||||
|
? (_timeSpan.inMinutes % 60).toString() + 'm'
|
||||||
|
: '');
|
||||||
return Row(children: [
|
return Row(children: [
|
||||||
// Container(),
|
// Container(),
|
||||||
(selecting)
|
(selecting)
|
||||||
@@ -132,54 +225,84 @@ class _ActivitiesState extends State<Activities> {
|
|||||||
Card(
|
Card(
|
||||||
|
|
||||||
// color: color,
|
// color: color,
|
||||||
elevation:20,
|
elevation: 20,
|
||||||
shadowColor: color,
|
shadowColor: color,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
//Open Respective Category
|
//Open Respective Category
|
||||||
if(selecting){
|
if (selecting) {
|
||||||
OnItemSelected(activity);
|
OnItemSelected(activity);
|
||||||
}
|
}
|
||||||
setState(() {
|
setState(() {});
|
||||||
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
onLongPress: () {
|
onLongPress: () {
|
||||||
print('gonna delete');
|
print('gonna delete');
|
||||||
selecting = !selecting;
|
selecting = !selecting;
|
||||||
selectedActivities = [activity];
|
selectedActivities = [activity];
|
||||||
setState(() {});
|
setState(() {});
|
||||||
|
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.all(10),
|
padding: EdgeInsets.all(15),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(name + " ($timeSpan)",
|
Row(children: [
|
||||||
style: TextStyle(color: Colors.white)),
|
Text(name + " [$timeSpan]",
|
||||||
Text(dateFormat.format(sTime) + " - " + dateFormat.format(eTime)),
|
style: TextStyle( fontSize: 17)),
|
||||||
|
if (containsMetadata)
|
||||||
|
Icon(Icons.arrow_forward_outlined, size: 20,),
|
||||||
|
if (containsMetadata)
|
||||||
|
Text(activity.metadata ?? '',overflow: TextOverflow.clip,)
|
||||||
|
]),
|
||||||
|
|
||||||
// Icon(Icons.analytics, color: color, size: 20,),
|
// Icon(Icons.analytics, color: color, size: 20,),
|
||||||
Icon(Icons.circle,
|
|
||||||
color: (productive)
|
|
||||||
? Colors.green
|
|
||||||
: Colors.red)
|
|
||||||
]),
|
]),
|
||||||
|
SizedBox(
|
||||||
|
height: 5,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(dateFormat.format(sTime) +
|
||||||
|
" - " +
|
||||||
|
dateFormat.format(eTime)),
|
||||||
|
SizedBox(
|
||||||
|
width: 20,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10, vertical: 2),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
color: (productive)
|
||||||
|
? Colors.green
|
||||||
|
: Colors.red),
|
||||||
|
child: Text(
|
||||||
|
activity.taskType.cat?.name ?? 'n/a'))
|
||||||
|
// Icon(Icons.circle,
|
||||||
|
// color: (productive)
|
||||||
|
// ? Colors.green
|
||||||
|
// : Colors.red)
|
||||||
|
])
|
||||||
],
|
],
|
||||||
)))),
|
)))),
|
||||||
Container(
|
Container(
|
||||||
margin: EdgeInsets.fromLTRB(15, 0, 15, 10),
|
margin: EdgeInsets.fromLTRB(15, 0, 15, 10),
|
||||||
height: 2,
|
height: 2,
|
||||||
color: color)
|
child:Row(children: [
|
||||||
|
Expanded(flex:timePercentage ,child: Container(color:color)),
|
||||||
|
Expanded(flex:100-timePercentage,child:Container())
|
||||||
|
],)),
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnItemSelected(Activity activity){
|
void OnItemSelected(Activity activity) {
|
||||||
if (!selectedActivities.contains(activity)) {
|
if (!selectedActivities.contains(activity)) {
|
||||||
selectedActivities.add(activity);
|
selectedActivities.add(activity);
|
||||||
} else {
|
} else {
|
||||||
@@ -187,23 +310,25 @@ class _ActivitiesState extends State<Activities> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteSelectedTasks() async{
|
void DeleteSelectedTasks() async {
|
||||||
progressDialog.show(max: 100, msg: 'Deleteing ${selectedActivities.length} Task Types');
|
progressDialog.show(
|
||||||
|
max: 100, msg: 'Deleteing ${selectedActivities.length} Activities');
|
||||||
selectedActivities.forEach((element) async {
|
selectedActivities.forEach((element) async {
|
||||||
await User.UserOperations.deleteActivity(element, bulk:true);
|
await User.UserOperations.deleteActivity(element, bulk: true);
|
||||||
});
|
});
|
||||||
|
|
||||||
await Future.delayed(Duration(seconds: 2));
|
await Future.delayed(Duration(seconds: 2));
|
||||||
await User.UserOperations.executeQueries();
|
await User.UserOperations.executeQueries();
|
||||||
await User.updateActList();
|
await User.updateActList();
|
||||||
selectedActivities=[];
|
selectedActivities = [];
|
||||||
selecting=false;
|
selecting = false;
|
||||||
setState(() {
|
setState(() {
|
||||||
progressDialog.update(value: 100);
|
progressDialog.update(value: 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Activity> selectedActivities = [];
|
List<Activity> selectedActivities = [];
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ class _CategoriesState extends State<Categories> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(name,
|
Text(name,
|
||||||
style: TextStyle(color: Colors.white)),
|
),
|
||||||
// Icon(Icons.analytics, color: color, size: 20,),
|
// Icon(Icons.analytics, color: color, size: 20,),
|
||||||
Icon(Icons.circle,
|
Icon(Icons.circle,
|
||||||
color: (productive)
|
color: (productive)
|
||||||
|
|||||||
@@ -31,15 +31,17 @@ class TaskType{
|
|||||||
|
|
||||||
class Activity{
|
class Activity{
|
||||||
|
|
||||||
Activity(this.taskType, this.startTime, this.endTime);
|
Activity(this.taskType, this.startTime, this.endTime, {this.metadata});
|
||||||
|
|
||||||
TaskType taskType;
|
TaskType taskType;
|
||||||
DateTime startTime;
|
DateTime startTime;
|
||||||
DateTime endTime;
|
DateTime endTime;
|
||||||
|
String? metadata;
|
||||||
|
|
||||||
static String colType = "type";
|
static String colType = "type";
|
||||||
static String colStartTime = "s_time";
|
static String colStartTime = "s_time";
|
||||||
static String colEndTime = "e_time";
|
static String colEndTime = "e_time";
|
||||||
|
static String colMetadata= "metadata";
|
||||||
}
|
}
|
||||||
|
|
||||||
class InitialData{
|
class InitialData{
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ class _TasksState extends State<Tasks> {
|
|||||||
} else {
|
} else {
|
||||||
Color color = HexColor.fromHex(element.cat?.color ?? '#000000');
|
Color color = HexColor.fromHex(element.cat?.color ?? '#000000');
|
||||||
bool productive = element.cat?.productive ?? true;
|
bool productive = element.cat?.productive ?? true;
|
||||||
Widget task = TaskCard(context, name, productive, color);
|
Widget task = TaskCard(context, name, productive, color, element.cat?.name ?? 'n/a');
|
||||||
_tasks.add(task);
|
_tasks.add(task);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -95,7 +95,7 @@ class _TasksState extends State<Tasks> {
|
|||||||
|
|
||||||
bool selecting = false;
|
bool selecting = false;
|
||||||
Widget TaskCard(
|
Widget TaskCard(
|
||||||
BuildContext context, String name, bool productive, Color color) {
|
BuildContext context, String name, bool productive, Color color, String catName) {
|
||||||
return Row(children: [
|
return Row(children: [
|
||||||
// Container(),
|
// Container(),
|
||||||
(selecting)
|
(selecting)
|
||||||
@@ -140,12 +140,16 @@ class _TasksState extends State<Tasks> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(name,
|
Text(name,
|
||||||
style: TextStyle(color: Colors.white)),
|
),
|
||||||
// Icon(Icons.analytics, color: color, size: 20,),
|
// Icon(Icons.analytics, color: color, size: 20,),
|
||||||
Icon(Icons.circle,
|
Container(
|
||||||
color: (productive)
|
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||||
? Colors.green
|
decoration: BoxDecoration(
|
||||||
: Colors.red)
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
color: (productive) ? Colors.green : Colors.red
|
||||||
|
),
|
||||||
|
child:Text(catName)
|
||||||
|
)
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
)))),
|
)))),
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ Future<void> initUserData() async {
|
|||||||
print('Going offline mode.');
|
print('Going offline mode.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bool userDataInitiated =false;
|
||||||
Future<void> refreshUserData() async{
|
Future<void> refreshUserData() async{
|
||||||
ShowProgress("Loading data");
|
ShowProgress("Loading data");
|
||||||
// categories= await GetCategories(true);
|
// categories= await GetCategories(true);
|
||||||
@@ -70,6 +70,7 @@ Future<void> refreshUserData() async{
|
|||||||
await updateCatsList();
|
await updateCatsList();
|
||||||
await updateTasksList();
|
await updateTasksList();
|
||||||
await updateActList();
|
await updateActList();
|
||||||
|
userDataInitiated=true;
|
||||||
HideProgress();
|
HideProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +123,7 @@ void onCacheDatabaseCreate(Database db, int newVersion) async {
|
|||||||
await db.execute(TaskTableSQL);
|
await db.execute(TaskTableSQL);
|
||||||
|
|
||||||
String ActivityTableSQL =
|
String ActivityTableSQL =
|
||||||
'CREATE TABLE Activities(id INTEGER PRIMARY KEY AUTOINCREMENT, ${Activity.colType} INT, ${Activity.colStartTime} DATETIME, ${Activity.colEndTime} DATETIME, '
|
'CREATE TABLE Activities(id INTEGER PRIMARY KEY AUTOINCREMENT, ${Activity.colType} INT, ${Activity.colStartTime} DATETIME, ${Activity.colEndTime} DATETIME, ${Activity.colMetadata} TEXT, '
|
||||||
'FOREIGN KEY (${Activity.colType}) REFERENCES TaskTypes(id))';
|
'FOREIGN KEY (${Activity.colType}) REFERENCES TaskTypes(id))';
|
||||||
// print(ActivityTableSQL);
|
// print(ActivityTableSQL);
|
||||||
await db.execute(ActivityTableSQL);
|
await db.execute(ActivityTableSQL);
|
||||||
@@ -328,7 +329,7 @@ Future<List<Activity>> GetActivities(bool forceOffline) async{
|
|||||||
List<Activity> _activities = [];
|
List<Activity> _activities = [];
|
||||||
if(offline || forceOffline){
|
if(offline || forceOffline){
|
||||||
//Retreive from cacheDB
|
//Retreive from cacheDB
|
||||||
|
print('offline, refreshing activities');
|
||||||
}else{
|
}else{
|
||||||
//Check if server got updated, If not go for cache
|
//Check if server got updated, If not go for cache
|
||||||
var android_id = await Settings.UUID();
|
var android_id = await Settings.UUID();
|
||||||
@@ -359,14 +360,15 @@ Future<List<Activity>> GetActivities(bool forceOffline) async{
|
|||||||
String? type = element[Activity.colType].toString();
|
String? type = element[Activity.colType].toString();
|
||||||
String? startTime = element[Activity.colStartTime].toString();
|
String? startTime = element[Activity.colStartTime].toString();
|
||||||
String? endTime = element[Activity.colEndTime].toString();
|
String? endTime = element[Activity.colEndTime].toString();
|
||||||
|
String? metadata = element[Activity.colMetadata].toString();
|
||||||
TaskType? taskType = await getTaskFromId(type);
|
TaskType? taskType = await getTaskFromId(type);
|
||||||
if(type==null || startTime==null || endTime==null || taskType==null){
|
if(type==null || startTime==null || endTime==null || taskType==null){
|
||||||
print("Something is null!");
|
print("Something is null!\ntype:${type==null}, startTime:${startTime==null}, eTime:${endTime==null}, taskType${taskType==null}");
|
||||||
print("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}");
|
print("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}, metadata:${metadata}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
print("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}");
|
print("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}, metadata:${metadata}");
|
||||||
_activities.add(Activity(taskType, DateTime.parse(startTime), DateTime.parse(endTime)));
|
_activities.add(Activity(taskType, DateTime.parse(startTime), DateTime.parse(endTime), metadata: metadata));
|
||||||
}
|
}
|
||||||
activities = _activities;
|
activities = _activities;
|
||||||
return activities;
|
return activities;
|
||||||
@@ -395,8 +397,8 @@ Future<void> UpdateActivitiesFromServer() async{
|
|||||||
Map<String, dynamic> cat = jsonDecode(value);
|
Map<String, dynamic> cat = jsonDecode(value);
|
||||||
print(cat);
|
print(cat);
|
||||||
await cacheDb.rawInsert(
|
await cacheDb.rawInsert(
|
||||||
"INSERT OR REPLACE INTO Activities (${Activity.colType}, ${Activity.colStartTime}, ${Activity.colEndTime}) "
|
"INSERT OR REPLACE INTO Activities (${Activity.colType}, ${Activity.colStartTime}, ${Activity.colEndTime}, ${Activity.colMetadata}) "
|
||||||
"VALUES ('${cat['task_id']}', '${cat['sTime']}','${cat['eTime']}') ");
|
"VALUES ('${cat['task_id']}', '${cat['sTime']}','${cat['eTime']}', '${cat['metadata']}') ");
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
print("No activities for now");
|
print("No activities for now");
|
||||||
@@ -410,13 +412,15 @@ Future<void> UpdateActivitiesFromServer() async{
|
|||||||
Future<TaskType?> getTaskFromId(String taskId) async{
|
Future<TaskType?> getTaskFromId(String taskId) async{
|
||||||
// await GetTaskTypes(false);
|
// await GetTaskTypes(false);
|
||||||
TaskType? cat = null;
|
TaskType? cat = null;
|
||||||
taskTypes.forEach((element) async{
|
for (var element in taskTypes){
|
||||||
if(element.id == taskId){
|
if(element.id == taskId){
|
||||||
cat= element;
|
cat= element;
|
||||||
|
|
||||||
cat?.cat = await getCatFromId((cat?.category ?? ''));
|
cat?.cat = await getCatFromId((cat?.category ?? ''));
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
if(cat==null){
|
||||||
|
print('Got null tasktype for ${taskId} after searching on ${taskTypes.length}');
|
||||||
|
}
|
||||||
|
|
||||||
return cat;
|
return cat;
|
||||||
}
|
}
|
||||||
@@ -424,11 +428,11 @@ Future<TaskType?> getTaskFromId(String taskId) async{
|
|||||||
Future<Category?> getCatFromId(String catId) async{
|
Future<Category?> getCatFromId(String catId) async{
|
||||||
// await GetTaskTypes(false);
|
// await GetTaskTypes(false);
|
||||||
Category? cat = null;
|
Category? cat = null;
|
||||||
categories.forEach((element) {
|
for (var element in categories) {
|
||||||
if(element.category_id == catId){
|
if(element.category_id == catId){
|
||||||
cat= element;
|
cat= element;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
return cat;
|
return cat;
|
||||||
}
|
}
|
||||||
@@ -519,7 +523,7 @@ class UserOperations{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> addActivity(String type, String sTime,String eTime, {bool bulk = false, Function(int)? onOverlap}) async{
|
static Future<void> addActivity(String type, String sTime,String eTime, {String metadata = 'null',bool bulk = false, Function(int)? onOverlap}) async{
|
||||||
//Check for timeoverlapse
|
//Check for timeoverlapse
|
||||||
activities= await GetActivities(true);
|
activities= await GetActivities(true);
|
||||||
int? overlapCount = Sqflite.firstIntValue(await cacheDb.rawQuery("SELECT COUNT(*) FROM Activities WHERE (((${Activity.colStartTime} < datetime('$sTime')) AND ((${Activity.colEndTime} > datetime('$eTime')) OR (${Activity.colEndTime} < datetime('$eTime') AND ${Activity.colEndTime} > datetime('$sTime')))) OR (${Activity.colStartTime} > datetime('$sTime') AND ${Activity.colStartTime} < datetime('$eTime')) OR (${Activity.colStartTime}=datetime('$sTime') AND ${Activity.colEndTime}=datetime('$eTime')))"));
|
int? overlapCount = Sqflite.firstIntValue(await cacheDb.rawQuery("SELECT COUNT(*) FROM Activities WHERE (((${Activity.colStartTime} < datetime('$sTime')) AND ((${Activity.colEndTime} > datetime('$eTime')) OR (${Activity.colEndTime} < datetime('$eTime') AND ${Activity.colEndTime} > datetime('$sTime')))) OR (${Activity.colStartTime} > datetime('$sTime') AND ${Activity.colStartTime} < datetime('$eTime')) OR (${Activity.colStartTime}=datetime('$sTime') AND ${Activity.colEndTime}=datetime('$eTime')))"));
|
||||||
@@ -533,8 +537,13 @@ class UserOperations{
|
|||||||
'device_id': await Settings.UUID(),
|
'device_id': await Settings.UUID(),
|
||||||
'type' : username+type,
|
'type' : username+type,
|
||||||
'sTime': sTime,
|
'sTime': sTime,
|
||||||
'eTime':eTime
|
'eTime':eTime,
|
||||||
|
'metadata': metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if(metadata.length > 0){
|
||||||
|
|
||||||
|
}
|
||||||
//Add Query
|
//Add Query
|
||||||
Map<String,Object> query = {
|
Map<String,Object> query = {
|
||||||
Queries.colLink: 'add_activity',
|
Queries.colLink: 'add_activity',
|
||||||
@@ -547,12 +556,13 @@ class UserOperations{
|
|||||||
|
|
||||||
//update Cache
|
//update Cache
|
||||||
Map<String,Object> data = {
|
Map<String,Object> data = {
|
||||||
Activity.colType: type,
|
Activity.colType: username+type,
|
||||||
Activity.colStartTime: sTime,
|
Activity.colStartTime: sTime,
|
||||||
Activity.colEndTime: eTime
|
Activity.colEndTime: eTime,
|
||||||
|
Activity.colMetadata: metadata
|
||||||
};
|
};
|
||||||
await cacheDb.insert('Activities', data);
|
await cacheDb.insert('Activities', data);
|
||||||
await GetActivities(true);
|
activities= await GetActivities(false);
|
||||||
if(!bulk){
|
if(!bulk){
|
||||||
//Add to server and refresh Cache
|
//Add to server and refresh Cache
|
||||||
await executeQueries();
|
await executeQueries();
|
||||||
@@ -688,10 +698,10 @@ class UserOperations{
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ShowProgress(msg){
|
void ShowProgress(msg){
|
||||||
try{progressDialog?.show(max: 100, msg: msg);}catch(e){}
|
//try{progressDialog?.show(max: 100, msg: msg);}catch(e){}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HideProgress(){
|
void HideProgress(){
|
||||||
try{progressDialog?.update(value: 100);}catch(e){}
|
// try{progressDialog?.update(value: 100);}catch(e){}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
816
lib/main.dart
@@ -1,25 +1,28 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
import 'package:tasktracker/Categories.dart';
|
import 'package:tasktracker/Categories.dart';
|
||||||
import 'package:tasktracker/Welcome.dart';
|
import 'package:tasktracker/Welcome.dart';
|
||||||
import 'package:tasktracker/splash.dart';
|
import 'package:tasktracker/splash.dart';
|
||||||
import 'package:wakelock/wakelock.dart';
|
import 'package:wakelock/wakelock.dart';
|
||||||
import 'package:charts_flutter/flutter.dart' as charts;
|
import 'Data.dart';
|
||||||
import 'NewTask.dart';
|
import 'NewTask.dart';
|
||||||
import 'newActivity.dart';
|
import 'newActivity.dart';
|
||||||
import 'Tasks.dart';
|
import 'Tasks.dart';
|
||||||
import 'Activities.dart';
|
import 'Activities.dart';
|
||||||
import 'User.dart' as User;
|
import 'User.dart' as User;
|
||||||
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
|
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
|
||||||
|
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||||
|
|
||||||
late ProgressDialog progressDialog;
|
late ProgressDialog progressDialog;
|
||||||
|
|
||||||
showAlertDialog(BuildContext context, String title, String message) {
|
showAlertDialog(BuildContext context, String title, String message) {
|
||||||
|
|
||||||
// set up the button
|
// set up the button
|
||||||
Widget okButton = TextButton(
|
Widget okButton = TextButton(
|
||||||
child: Text("OK"),
|
child: Text("OK"),
|
||||||
onPressed: () { Navigator.of(context).pop(); },
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// set up the AlertDialog
|
// set up the AlertDialog
|
||||||
@@ -57,26 +60,6 @@ extension HexColor on Color {
|
|||||||
'${blue.toRadixString(16).padLeft(2, '0')}';
|
'${blue.toRadixString(16).padLeft(2, '0')}';
|
||||||
}
|
}
|
||||||
|
|
||||||
// To keep the screen on:
|
|
||||||
final List<PopulationData> data = [
|
|
||||||
PopulationData(
|
|
||||||
name: "Rocket League",
|
|
||||||
value: 45,
|
|
||||||
barColor: charts.ColorUtil.fromDartColor(Colors.blue)),
|
|
||||||
PopulationData(
|
|
||||||
name: "CS:GO",
|
|
||||||
value: 15,
|
|
||||||
barColor: charts.ColorUtil.fromDartColor(Colors.yellow)),
|
|
||||||
PopulationData(
|
|
||||||
name: "Halo",
|
|
||||||
value: 10,
|
|
||||||
barColor: charts.ColorUtil.fromDartColor(Colors.grey)),
|
|
||||||
PopulationData(
|
|
||||||
name: "SneakyPeaky",
|
|
||||||
value: 30,
|
|
||||||
barColor: charts.ColorUtil.fromDartColor(Colors.red)),
|
|
||||||
];
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
//Wakelock.enable(); // or Wakelock.toggle(on: true);
|
//Wakelock.enable(); // or Wakelock.toggle(on: true);
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
@@ -88,26 +71,52 @@ class MyApp extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: 'Flutter Demo',
|
title: 'Flutter Demo',
|
||||||
theme: ThemeData(
|
theme: ThemeData(accentColor: Colors.redAccent, brightness: Brightness.dark, primaryColor: Colors.amber, fontFamily: 'Noto-Sans'),
|
||||||
accentColor: Colors.redAccent,
|
//home: const MyHomePage(),
|
||||||
brightness: Brightness.dark,
|
initialRoute: '/splash',
|
||||||
primaryColor: Colors.amber,
|
routes: {
|
||||||
fontFamily: 'Noto-Sans'),
|
'/splash': (context) => const SplashScreen(),
|
||||||
//home: const MyHomePage(),
|
'/welcome': (context) => const WelcomePage(),
|
||||||
initialRoute: '/splash',
|
'/': (context) => const MyHomePage(),
|
||||||
routes:{
|
'/Tasks': (context) => const Tasks(),
|
||||||
'/splash':(context)=> const SplashScreen(),
|
'/Categories': (context) => const Categories(),
|
||||||
'/welcome':(context)=> const WelcomePage(),
|
'/Activities': (context) => const Activities()
|
||||||
'/':(context) => const MyHomePage(),
|
});
|
||||||
'/Tasks':(context)=> const Tasks(),
|
|
||||||
'/Categories':(context)=>const Categories(),
|
|
||||||
'/Activities':(context)=>const Activities()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<String> days = [];
|
||||||
|
String curDay = "";
|
||||||
|
|
||||||
|
DateTime? firstDay = null;
|
||||||
|
DateTime? lastDay = null;
|
||||||
|
DateTimeRange? taskTypeRange = null;
|
||||||
|
DateTimeRange? catsRange = null;
|
||||||
|
|
||||||
|
List<ProductivityMapData> productivityData = <ProductivityMapData>[
|
||||||
|
ProductivityMapData('02/24', 35),
|
||||||
|
ProductivityMapData('02/25', 28),
|
||||||
|
ProductivityMapData('02/26', 34),
|
||||||
|
ProductivityMapData('02/27', 32),
|
||||||
|
ProductivityMapData('02/28', 40)
|
||||||
|
];
|
||||||
|
|
||||||
|
List<TaskTypeMapData> taskTypesData = <TaskTypeMapData>[TaskTypeMapData('Eat', 3600, Colors.green), TaskTypeMapData('Play', 300, Colors.blue)];
|
||||||
|
List<CatMapData> catsData = <CatMapData>[
|
||||||
|
CatMapData('Jan', 35, Colors.green),
|
||||||
|
CatMapData('Feb', 28, Colors.blueAccent),
|
||||||
|
CatMapData('Mar', 34, Colors.yellow),
|
||||||
|
CatMapData('Apr', 32, Colors.grey),
|
||||||
|
];
|
||||||
|
|
||||||
|
List<CatMapData> dailyData = <CatMapData>[
|
||||||
|
CatMapData('Jan', 35, Colors.green),
|
||||||
|
CatMapData('Feb', 28, Colors.blueAccent),
|
||||||
|
CatMapData('Mar', 34, Colors.yellow),
|
||||||
|
CatMapData('Apr', 32, Colors.grey),
|
||||||
|
];
|
||||||
|
|
||||||
class MyHomePage extends StatefulWidget {
|
class MyHomePage extends StatefulWidget {
|
||||||
const MyHomePage({Key? key}) : super(key: key);
|
const MyHomePage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@@ -116,215 +125,572 @@ class MyHomePage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _MyHomePageState extends State<MyHomePage> {
|
class _MyHomePageState extends State<MyHomePage> {
|
||||||
List<charts.Series<PopulationData, String>> series = [
|
|
||||||
charts.Series(
|
|
||||||
id: "Subscribers",
|
|
||||||
data: data,
|
|
||||||
domainFn: (PopulationData series, _) => series.name,
|
|
||||||
measureFn: (PopulationData series, _) => series.value,
|
|
||||||
colorFn: (PopulationData series, _) => series.barColor)
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
// TODO: implement initState
|
// TODO: implement initState
|
||||||
super.initState();
|
super.initState();
|
||||||
|
User.refreshUserData().then((val) => LoadStats());
|
||||||
showOfflineSnack();
|
// showOfflineSnack();
|
||||||
progressDialog = ProgressDialog(context: context);
|
LoadStats();
|
||||||
User.progressDialog=progressDialog;
|
// progressDialog = ProgressDialog(context: context);
|
||||||
|
// User.progressDialog=progressDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
void showOfflineSnack() async{
|
void LoadStats() async {
|
||||||
|
// return;
|
||||||
|
|
||||||
|
while (!User.userDataInitiated) {
|
||||||
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
DateFormat dFormat = DateFormat("MM/dd");
|
||||||
|
Map<Category, int> catTimeMap = <Category, int>{};
|
||||||
|
Map<Category, int> catBriefMap = <Category, int>{};
|
||||||
|
|
||||||
|
Map<String, int> productivtyActs = <String, int>{};
|
||||||
|
Map<String, int> unproductivtyActs = <String, int>{};
|
||||||
|
Map<TaskType, int> taskTypesDuration = <TaskType, int>{};
|
||||||
|
firstDay = null;
|
||||||
|
lastDay = null;
|
||||||
|
String lastDate = "";
|
||||||
|
for (var element in User.activities) {
|
||||||
|
if (lastDay == null) {
|
||||||
|
lastDay = element.endTime;
|
||||||
|
}
|
||||||
|
if (taskTypeRange == null) {
|
||||||
|
print("$lastDay - $firstDay");
|
||||||
|
taskTypeRange = DateTimeRange(start: lastDay!.subtract(const Duration(days: 1)), end: lastDay!);
|
||||||
|
}
|
||||||
|
if (catsRange == null) {
|
||||||
|
print("$lastDay - $firstDay");
|
||||||
|
catsRange = DateTimeRange(start: lastDay!.subtract(const Duration(days: 1)), end: lastDay!);
|
||||||
|
}
|
||||||
|
firstDay = element.startTime;
|
||||||
|
String thisDate = dFormat.format(element.startTime);
|
||||||
|
int thisMinutes = element.endTime.difference(element.startTime).inMinutes;
|
||||||
|
if (!days.contains(thisDate)) {
|
||||||
|
days.add(dFormat.format(element.startTime));
|
||||||
|
}
|
||||||
|
if (curDay == "") {
|
||||||
|
curDay = dFormat.format(DateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((element.startTime.isAfter(taskTypeRange!.start) && element.startTime.isBefore(taskTypeRange!.end)) ||
|
||||||
|
(dFormat.format(element.startTime) == dFormat.format(taskTypeRange!.start) || dFormat.format(element.startTime) == dFormat.format(taskTypeRange!.end))) {
|
||||||
|
if (taskTypesDuration.containsKey(element.taskType)) {
|
||||||
|
taskTypesDuration[element.taskType] = taskTypesDuration[element.taskType]! + thisMinutes;
|
||||||
|
} else {
|
||||||
|
taskTypesDuration.putIfAbsent(element.taskType, () => thisMinutes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.taskType.cat?.productive ?? false) {
|
||||||
|
if (productivtyActs.containsKey(thisDate)) {
|
||||||
|
productivtyActs[thisDate] = (productivtyActs[thisDate]! + thisMinutes);
|
||||||
|
} else {
|
||||||
|
productivtyActs.putIfAbsent(thisDate, () => thisMinutes);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (unproductivtyActs.containsKey(thisDate)) {
|
||||||
|
unproductivtyActs[thisDate] = (unproductivtyActs[thisDate]! + thisMinutes);
|
||||||
|
} else {
|
||||||
|
unproductivtyActs.putIfAbsent(thisDate, () => thisMinutes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thisDate == curDay) {
|
||||||
|
if (element.taskType.cat == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
print("Null : ${thisMinutes}");
|
||||||
|
if (catTimeMap.containsKey(element.taskType.cat)) {
|
||||||
|
catTimeMap[element.taskType.cat!] = (catTimeMap[element.taskType.cat]! + thisMinutes);
|
||||||
|
} else {
|
||||||
|
catTimeMap.putIfAbsent(element.taskType.cat!, () => thisMinutes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((element.startTime.isAfter(catsRange!.start) && element.startTime.isBefore(catsRange!.end)) ||
|
||||||
|
(dFormat.format(element.startTime) == dFormat.format(catsRange!.start) || dFormat.format(element.startTime) == dFormat.format(catsRange!.end))) {
|
||||||
|
if (element.taskType.cat == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
print("Null : ${thisMinutes}");
|
||||||
|
if (catBriefMap.containsKey(element.taskType.cat)) {
|
||||||
|
catBriefMap[element.taskType.cat!] = (catBriefMap[element.taskType.cat]! + thisMinutes);
|
||||||
|
} else {
|
||||||
|
catBriefMap.putIfAbsent(element.taskType.cat!, () => thisMinutes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//curDay = days[0];
|
||||||
|
if (this.mounted) {
|
||||||
|
setState(() {
|
||||||
|
dailyData = <CatMapData>[];
|
||||||
|
productivityData = <ProductivityMapData>[];
|
||||||
|
taskTypesData = <TaskTypeMapData>[];
|
||||||
|
catsData = <CatMapData>[];
|
||||||
|
|
||||||
|
catTimeMap.forEach((key, value) {
|
||||||
|
print(key.name + " : $value");
|
||||||
|
Color barCol = HexColor.fromHex(key.color);
|
||||||
|
dailyData.add(CatMapData(key.name, value, barCol));
|
||||||
|
});
|
||||||
|
|
||||||
|
for (var element in days) {
|
||||||
|
// if(productivtyActs.containsKey(element) && unproductivtyActs.containsKey(element)){
|
||||||
|
int prodActs = (productivtyActs[element] ?? 0);
|
||||||
|
int unprodActs = (unproductivtyActs[element] ?? 0);
|
||||||
|
double prod = (prodActs / (prodActs + unprodActs)) * 100;
|
||||||
|
productivityData.add(ProductivityMapData(element, prod));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
taskTypesDuration.forEach((key, value) {
|
||||||
|
print("$key : $value");
|
||||||
|
taskTypesData.add(TaskTypeMapData(key.name, value, HexColor.fromHex(key.cat!.color)));
|
||||||
|
});
|
||||||
|
|
||||||
|
catBriefMap.forEach((key, value) {
|
||||||
|
print(key.name + " : $value");
|
||||||
|
Color barCol = HexColor.fromHex(key.color);
|
||||||
|
catsData.add(CatMapData(key.name, value, barCol));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void showOfflineSnack() async {
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
if(User.offline){
|
if (User.offline) {
|
||||||
const SnackBar offlineSnack = SnackBar(content: Text('Offline'),duration: Duration(seconds: 100),);
|
const SnackBar offlineSnack = SnackBar(
|
||||||
ScaffoldMessenger.of(context).showSnackBar(offlineSnack);
|
content: Text('Offline'),
|
||||||
|
duration: Duration(seconds: 100),
|
||||||
|
);
|
||||||
|
// ScaffoldMessenger.of(context).showSnackBar(offlineSnack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
floatingActionButton: FloatingActionButton.extended(onPressed: (){
|
floatingActionButton: FloatingActionButton.extended(
|
||||||
Navigator.of(context).push(MaterialPageRoute(builder: (context)=> NewActivity()));
|
onPressed: () {
|
||||||
},
|
Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewActivity())).then((value) => {User.refreshUserData().then((va) => LoadStats())});
|
||||||
|
},
|
||||||
label: Text("New Activity"),
|
label: Text("New Activity"),
|
||||||
icon: Icon(Icons.add)
|
icon: Icon(Icons.add)),
|
||||||
),
|
appBar: AppBar(title: Row(children: [Icon(Icons.article_outlined, color: Theme.of(context).primaryColor), SizedBox(width: 10), Text('Summary')])),
|
||||||
appBar: AppBar(title: Row(children:[Icon(Icons.article_outlined, color: Theme.of(context).primaryColor),SizedBox(width: 10),Text('Summary')])),
|
drawer: navDrawer(context, 0),
|
||||||
drawer: navDrawer(context,0),
|
body: SafeArea(
|
||||||
body: SafeArea(
|
child: SingleChildScrollView(
|
||||||
child: Container(
|
scrollDirection: Axis.vertical,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
(false)
|
||||||
height: 300,
|
? Container(
|
||||||
padding: EdgeInsets.all(20),
|
padding: EdgeInsets.all(20),
|
||||||
child: Card(
|
child: Row(
|
||||||
elevation: 8,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
shadowColor: Colors.blueGrey,
|
mainAxisSize: MainAxisSize.max,
|
||||||
child: Padding(
|
children: [
|
||||||
padding: EdgeInsets.all(8),
|
Text("Good\nMorning!", style: TextStyle(fontSize: 23, fontStyle: FontStyle.italic)),
|
||||||
child: Column(
|
Text(
|
||||||
children: [
|
"12%",
|
||||||
cardTitle('Daily Average'),
|
style: TextStyle(fontSize: 30),
|
||||||
Expanded(
|
),
|
||||||
child: charts.BarChart(
|
Column(
|
||||||
series,
|
children: [
|
||||||
animate: true,
|
Text(DateFormat("yy - MM-dd").format(DateTime.now())),
|
||||||
barRendererDecorator:
|
Text(DateFormat("HH:mm").format(DateTime.now()), style: TextStyle(fontSize: 40)),
|
||||||
new charts.BarLabelDecorator(
|
],
|
||||||
labelPosition:
|
)
|
||||||
charts.BarLabelPosition.inside,
|
],
|
||||||
labelPadding: 10,
|
),
|
||||||
labelAnchor:
|
)
|
||||||
charts.BarLabelAnchor.middle),
|
: Container(),
|
||||||
))
|
Container(
|
||||||
],
|
height: 300,
|
||||||
)))),
|
padding: EdgeInsets.all(10),
|
||||||
Container(
|
child: Card(
|
||||||
height: 300,
|
elevation: 8,
|
||||||
padding: EdgeInsets.all(20),
|
shadowColor: Colors.blueGrey,
|
||||||
child: Card(
|
child: Padding(
|
||||||
elevation: 8,
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 20),
|
||||||
shadowColor: Colors.green,
|
child: Column(
|
||||||
child: Padding(
|
children: [
|
||||||
padding: EdgeInsets.all(8),
|
Row(
|
||||||
child: Column(
|
children: [
|
||||||
children: [
|
SizedBox(
|
||||||
cardTitle('Weekly Average'),
|
width: 10,
|
||||||
Expanded(
|
),
|
||||||
child: charts.BarChart(
|
Text("Productivity", style: TextStyle(color: Colors.green, fontWeight: FontWeight.bold)),
|
||||||
series,
|
],
|
||||||
animate: true,
|
),
|
||||||
barRendererDecorator:
|
Divider(),
|
||||||
new charts.BarLabelDecorator(
|
Row(
|
||||||
labelPosition:
|
mainAxisSize: MainAxisSize.max,
|
||||||
charts.BarLabelPosition.inside,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
labelPadding: 10,
|
children: [
|
||||||
labelAnchor:
|
Row(
|
||||||
charts.BarLabelAnchor.middle),
|
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
|
||||||
|
dataSource: productivityData.reversed.toList(),
|
||||||
|
xValueMapper: (ProductivityMapData sales, _) => sales.day,
|
||||||
|
yValueMapper: (ProductivityMapData sales, _) => sales.productivity,
|
||||||
|
color: Colors.green)
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 370,
|
||||||
|
padding: EdgeInsets.all(10),
|
||||||
|
child: Card(
|
||||||
|
elevation: 8,
|
||||||
|
shadowColor: Colors.blueGrey,
|
||||||
|
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), 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))
|
||||||
|
]))
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: [CircularProgressIndicator()])))),
|
||||||
|
Container(
|
||||||
|
height: 450,
|
||||||
|
padding: EdgeInsets.all(10),
|
||||||
|
child: Card(
|
||||||
|
elevation: 8,
|
||||||
|
shadowColor: Colors.blueGrey,
|
||||||
|
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: 450,
|
||||||
|
padding: EdgeInsets.all(10),
|
||||||
|
child: Card(
|
||||||
|
elevation: 8,
|
||||||
|
shadowColor: Colors.blueGrey,
|
||||||
|
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))
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
])))),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
));
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget dayPickerWidget(List<String> list, {required String value, required Function(String value) onChange}) {
|
||||||
|
if (!list.contains(value)) {
|
||||||
|
print("resetting");
|
||||||
|
onChange(list[0]);
|
||||||
|
}
|
||||||
|
bool nextAvailable = (list.indexOf(value) < (list.length - 1));
|
||||||
|
bool prevAvailable = (list.indexOf(value) > 0);
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
InkWell(
|
||||||
|
onTap: () {
|
||||||
|
if (nextAvailable) {
|
||||||
|
onChange(list[list.indexOf(value) + 1]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
height: 40,
|
||||||
|
width: 40,
|
||||||
|
child: Icon(Icons.arrow_back_ios, size: 18, color: (nextAvailable) ? Colors.white : Colors.grey),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
value,
|
||||||
|
),
|
||||||
|
InkWell(
|
||||||
|
onTap: () {
|
||||||
|
if (prevAvailable) {
|
||||||
|
onChange(list[list.indexOf(value) - 1]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
height: 40,
|
||||||
|
width: 40,
|
||||||
|
child: Icon(Icons.arrow_forward_ios, size: 18, color: (prevAvailable) ? Colors.white : Colors.grey),
|
||||||
|
))
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget cardTitle(String title) {
|
Widget moreButton() {
|
||||||
return Row(
|
return MaterialButton(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
onPressed: () {},
|
||||||
children:[
|
color: Colors.green,
|
||||||
Padding(padding: EdgeInsets.all(20),child:Text(title,
|
child: Row(
|
||||||
style: TextStyle(fontWeight: FontWeight.bold))),
|
children: [Text('More'), Icon(Icons.keyboard_arrow_right)],
|
||||||
MaterialButton(onPressed: (){},child:moreButton())]);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget moreButton(){
|
Drawer navDrawer(BuildContext context, int pageIndex) {
|
||||||
return MaterialButton(
|
return Drawer(
|
||||||
onPressed: (){
|
child: ListView(
|
||||||
|
|
||||||
},
|
|
||||||
color: Colors.green,
|
|
||||||
child:Row(
|
|
||||||
children: [
|
children: [
|
||||||
Text('More'),Icon(Icons.keyboard_arrow_right)
|
Padding(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||||
|
Text("Time Tracker", style: TextStyle(fontSize: 25, color: Theme.of(context).accentColor, fontWeight: FontWeight.bold)),
|
||||||
|
Icon(
|
||||||
|
Icons.more_time,
|
||||||
|
size: 30,
|
||||||
|
),
|
||||||
|
])),
|
||||||
|
Divider(),
|
||||||
|
ListTile(
|
||||||
|
selected: (pageIndex == 0),
|
||||||
|
title: Text('Summary'),
|
||||||
|
leading: Icon(Icons.article_outlined, color: Theme.of(context).primaryColor),
|
||||||
|
onTap: () {
|
||||||
|
if (pageIndex == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Navigator.of(context).pushReplacementNamed('/');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// ListTile(
|
||||||
|
// selected: (pageIndex == 1),
|
||||||
|
// title: Text('Analytics'),
|
||||||
|
// leading: Icon(Icons.analytics_outlined,
|
||||||
|
// color: Theme.of(context).primaryColor),
|
||||||
|
// onTap: () {
|
||||||
|
// if (pageIndex == 1) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// // Navigator.of(context).pushReplacementNamed('/');
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
Divider(),
|
||||||
|
ListTile(
|
||||||
|
selected: (pageIndex == 2),
|
||||||
|
title: Text('Activities'),
|
||||||
|
leading: Icon(Icons.task, color: Theme.of(context).primaryColor),
|
||||||
|
onTap: () {
|
||||||
|
if (pageIndex == 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Navigator.of(context).pushReplacementNamed('/Activities');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
selected: (pageIndex == 3),
|
||||||
|
title: Text('Task Types'),
|
||||||
|
leading: Icon(Icons.task, color: Theme.of(context).primaryColor),
|
||||||
|
onTap: () {
|
||||||
|
if (pageIndex == 3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Navigator.of(context).pushReplacementNamed('/Tasks');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
selected: (pageIndex == 4),
|
||||||
|
title: Text('Categories'),
|
||||||
|
leading: Icon(Icons.account_tree_outlined, color: Theme.of(context).primaryColor),
|
||||||
|
onTap: () {
|
||||||
|
if (pageIndex == 4) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Navigator.of(context).pushReplacementNamed('/Categories');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Divider(),
|
||||||
|
ListTile(
|
||||||
|
selected: (pageIndex == 5),
|
||||||
|
title: Text('Settings'),
|
||||||
|
leading: Icon(Icons.settings, color: Colors.blueGrey),
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
selected: (pageIndex == 6),
|
||||||
|
title: Text('About'),
|
||||||
|
leading: Icon(Icons.help_outline_outlined),
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
class PopulationData {
|
class MyPlayerBar extends CustomPainter {
|
||||||
String name;
|
MyPlayerBar(this.max, this.value, {this.background = Colors.lightBlue, this.fill = Colors.blue});
|
||||||
int value;
|
|
||||||
charts.Color barColor;
|
Color background = Colors.lightBlue;
|
||||||
PopulationData(
|
Color fill = Colors.blue;
|
||||||
{required this.name, required this.value, required this.barColor});
|
final int max;
|
||||||
|
final int value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
Paint paint = Paint();
|
||||||
|
double cursor = (value * size.width) / max;
|
||||||
|
Radius cornerRadius = Radius.circular(10.0);
|
||||||
|
|
||||||
|
// Already played half color (your darker orange)
|
||||||
|
paint.color = background;
|
||||||
|
|
||||||
|
// Painting already played half
|
||||||
|
canvas.drawRRect(RRect.fromRectAndCorners(Rect.fromLTWH(0.0, 0.0, cursor, size.height), topLeft: cornerRadius, bottomLeft: cornerRadius), paint);
|
||||||
|
|
||||||
|
// Yet to play half color (your lighter orange)
|
||||||
|
paint.color = fill;
|
||||||
|
|
||||||
|
// Painting the remaining space
|
||||||
|
canvas.drawRRect(RRect.fromRectAndCorners(Rect.fromLTWH(cursor, 0.0, size.width - cursor, size.height), bottomRight: cornerRadius, topRight: cornerRadius), paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRepaint(CustomPainter oldDelegate) => true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Drawer navDrawer(BuildContext context, int pageIndex){
|
class CatMapData {
|
||||||
return Drawer(
|
CatMapData(this.name, this.time, this.color);
|
||||||
child: ListView(
|
final String name;
|
||||||
children: [
|
final int time;
|
||||||
Padding(
|
final Color color;
|
||||||
padding: EdgeInsets.all(16),
|
}
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
class ProductivityMapData {
|
||||||
children:[Text("Time Tracker",
|
ProductivityMapData(this.day, this.productivity);
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 25,
|
final String day;
|
||||||
color: Theme.of(context).accentColor,
|
final double productivity;
|
||||||
fontWeight: FontWeight.bold)),
|
}
|
||||||
Icon(Icons.more_time,size: 30,),
|
|
||||||
])
|
class TaskTypeMapData {
|
||||||
),
|
TaskTypeMapData(this.task, this.time, this.color);
|
||||||
Divider(),
|
final Color color;
|
||||||
ListTile(
|
final String task;
|
||||||
selected: (pageIndex == 0),
|
final int time;
|
||||||
title: Text('Summary'),
|
}
|
||||||
leading: Icon(Icons.article_outlined,color: Theme.of(context).primaryColor),
|
|
||||||
onTap: () {
|
String MinutesToTimeString(minutes) {
|
||||||
if(pageIndex==0){return;}
|
int hours = (minutes / 60).floor();
|
||||||
Navigator.of(context).pushReplacementNamed('/');
|
int mins = minutes % 60;
|
||||||
},
|
|
||||||
),
|
String str = "";
|
||||||
ListTile(
|
if (hours > 0) {
|
||||||
selected: (pageIndex == 1),
|
str += hours.toString() + "h";
|
||||||
title: Text('Analytics'),
|
}
|
||||||
leading: Icon(Icons.analytics_outlined,color: Theme.of(context).primaryColor),
|
if (mins > 0) {
|
||||||
onTap: () {
|
str += ((hours > 0) ? " " : "") + mins.toString() + "m";
|
||||||
if(pageIndex==1){return;}
|
}
|
||||||
// Navigator.of(context).pushReplacementNamed('/');
|
|
||||||
},
|
return str;
|
||||||
),
|
}
|
||||||
Divider(),
|
|
||||||
ListTile(
|
|
||||||
selected: (pageIndex == 2),
|
|
||||||
title: Text('Activities'),
|
|
||||||
leading: Icon(Icons.task,color: Theme.of(context).primaryColor),
|
|
||||||
onTap: () {
|
|
||||||
if(pageIndex==2){return;}
|
|
||||||
Navigator.of(context).pushReplacementNamed('/Activities');
|
|
||||||
},
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
selected: (pageIndex == 3),
|
|
||||||
title: Text('Task Types'),
|
|
||||||
leading: Icon(Icons.task,color: Theme.of(context).primaryColor),
|
|
||||||
onTap: () {
|
|
||||||
if(pageIndex==3){return;}
|
|
||||||
Navigator.of(context).pushReplacementNamed('/Tasks');
|
|
||||||
},
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
selected: (pageIndex == 4),
|
|
||||||
title: Text('Categories'),
|
|
||||||
leading: Icon(Icons.account_tree_outlined,color: Theme.of(context).primaryColor),
|
|
||||||
onTap: () {
|
|
||||||
if(pageIndex==4){return;}
|
|
||||||
Navigator.of(context).pushReplacementNamed('/Categories');
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Divider(),
|
|
||||||
ListTile(
|
|
||||||
selected: (pageIndex == 5),
|
|
||||||
title: Text('Settings'),
|
|
||||||
leading: Icon(Icons.settings,color: Colors.blueGrey),
|
|
||||||
onTap: () {
|
|
||||||
|
|
||||||
},
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
selected: (pageIndex == 6),
|
|
||||||
title: Text('About'),
|
|
||||||
leading: Icon(Icons.help_outline_outlined),
|
|
||||||
onTap: () {
|
|
||||||
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/painting.dart';
|
||||||
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
|
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'User.dart' as User;
|
import 'User.dart' as User;
|
||||||
@@ -31,6 +32,7 @@ class _NewActivity extends State<NewActivity> {
|
|||||||
|
|
||||||
DateTime startTime = DateTime.now();
|
DateTime startTime = DateTime.now();
|
||||||
DateTime endTime = DateTime.now().add(Duration(minutes: 30));
|
DateTime endTime = DateTime.now().add(Duration(minutes: 30));
|
||||||
|
TextEditingController metadataController = TextEditingController();
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@@ -50,6 +52,7 @@ class _NewActivity extends State<NewActivity> {
|
|||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.all(10),
|
padding: EdgeInsets.all(10),
|
||||||
child: Text('Task')),
|
child: Text('Task')),
|
||||||
|
|
||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
horizontal: 12, vertical: 1),
|
horizontal: 12, vertical: 1),
|
||||||
@@ -78,6 +81,25 @@ class _NewActivity extends State<NewActivity> {
|
|||||||
selectedCat = _value ?? 'n/a';
|
selectedCat = _value ?? 'n/a';
|
||||||
});
|
});
|
||||||
})),
|
})),
|
||||||
|
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.all(10),
|
||||||
|
child:Column(
|
||||||
|
children: [
|
||||||
|
|
||||||
|
TextField(
|
||||||
|
controller: metadataController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Description (optional)',
|
||||||
|
filled: true,
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(20)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
),
|
||||||
Container(
|
Container(
|
||||||
child: Divider(
|
child: Divider(
|
||||||
height: 30,
|
height: 30,
|
||||||
@@ -85,82 +107,107 @@ class _NewActivity extends State<NewActivity> {
|
|||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.all(10),
|
padding: EdgeInsets.all(10),
|
||||||
child: Text('Start Time')),
|
child: Text('Start Time')),
|
||||||
Container(
|
Row(
|
||||||
padding: EdgeInsets.symmetric(
|
mainAxisSize: MainAxisSize.max,
|
||||||
horizontal: 12, vertical: 1),
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
decoration: BoxDecoration(
|
children: [
|
||||||
borderRadius: BorderRadius.circular(12),
|
QuickTimeButton('Last', Function: (){
|
||||||
border: Border.all(
|
if(User.activities.length > 0) {
|
||||||
color: Colors.grey, width: 2)),
|
startTime= User.activities[0].endTime;
|
||||||
child: MaterialButton(
|
}
|
||||||
onPressed: () {
|
})
|
||||||
setState(() {
|
,
|
||||||
DatePicker.showDateTimePicker(
|
Container(
|
||||||
context,
|
padding: EdgeInsets.symmetric(
|
||||||
showTitleActions: true,
|
horizontal: 12, vertical: 1),
|
||||||
onChanged: (date) {
|
decoration: BoxDecoration(
|
||||||
// print('change $date');
|
borderRadius: BorderRadius.circular(12),
|
||||||
}, onConfirm: (date) {
|
border: Border.all(
|
||||||
|
color: Colors.grey, width: 2)),
|
||||||
|
child: MaterialButton(
|
||||||
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
if(endTime.compareTo(date) < 0){
|
DatePicker.showDateTimePicker(
|
||||||
const snackBar = SnackBar(
|
context,
|
||||||
content: Text('You cannot start something after you ended it!'),
|
showTitleActions: true,
|
||||||
);
|
onChanged: (date) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
// print('change $date');
|
||||||
}else {
|
}, onConfirm: (date) {
|
||||||
startTime = date;
|
setState(() {
|
||||||
}
|
if(endTime.compareTo(date) < 0){
|
||||||
|
const snackBar = SnackBar(
|
||||||
|
content: Text('You cannot start something after you ended it!'),
|
||||||
|
);
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
|
}else {
|
||||||
|
startTime = date;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
currentTime: startTime,
|
||||||
|
locale: LocaleType.en);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
currentTime: startTime,
|
child: Text(
|
||||||
locale: LocaleType.en);
|
dateFormat.format(startTime),
|
||||||
});
|
style: TextStyle(
|
||||||
},
|
color: Colors.blue)))),
|
||||||
child: Text(
|
QuickTimeButton('Now', Function: (){
|
||||||
dateFormat.format(startTime),
|
startTime = DateTime.now();
|
||||||
style: TextStyle(
|
})
|
||||||
color: Colors.blue)))),
|
],
|
||||||
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.all(10),
|
padding: EdgeInsets.all(10),
|
||||||
child: Text('Ended Time')),
|
child: Text('Ended Time')),
|
||||||
Container(
|
Row(
|
||||||
padding: EdgeInsets.symmetric(
|
mainAxisSize: MainAxisSize.max,
|
||||||
horizontal: 12, vertical: 1),
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
decoration: BoxDecoration(
|
children: [
|
||||||
borderRadius: BorderRadius.circular(12),
|
Container(width: 60,),
|
||||||
border: Border.all(
|
Container(
|
||||||
color: Colors.grey, width: 2)),
|
padding: EdgeInsets.symmetric(
|
||||||
child: MaterialButton(
|
horizontal: 12, vertical: 1),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.grey, width: 2)),
|
||||||
|
child: MaterialButton(
|
||||||
|
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
|
||||||
DatePicker.showDateTimePicker(
|
|
||||||
context,
|
|
||||||
showTitleActions: true,
|
|
||||||
onChanged: (date) {
|
|
||||||
// print('change $date');
|
|
||||||
}, onConfirm: (date) {
|
|
||||||
setState(() {
|
setState(() {
|
||||||
if(startTime.compareTo(date) > 0){
|
DatePicker.showDateTimePicker(
|
||||||
const snackBar = SnackBar(
|
context,
|
||||||
content: Text('You cannot end something before you start it!'),
|
showTitleActions: true,
|
||||||
);
|
onChanged: (date) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
// print('change $date');
|
||||||
}else {
|
}, onConfirm: (date) {
|
||||||
endTime = date;
|
setState(() {
|
||||||
}
|
if(startTime.compareTo(date) > 0){
|
||||||
|
const snackBar = SnackBar(
|
||||||
|
content: Text('You cannot end something before you start it!'),
|
||||||
|
);
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
|
}else {
|
||||||
|
endTime = date;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
currentTime: endTime,
|
||||||
|
locale: LocaleType.en);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
currentTime: endTime,
|
child: Text(dateFormat.format(endTime),
|
||||||
locale: LocaleType.en);
|
style: TextStyle(
|
||||||
});
|
color: Colors.blue)))),
|
||||||
},
|
QuickTimeButton('Now', Function: (){
|
||||||
child: Text(dateFormat.format(endTime),
|
endTime = DateTime.now();
|
||||||
style: TextStyle(
|
})
|
||||||
color: Colors.blue)))),
|
],
|
||||||
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 30,
|
height: 30,
|
||||||
),
|
),
|
||||||
@@ -173,6 +220,12 @@ class _NewActivity extends State<NewActivity> {
|
|||||||
Divider(
|
Divider(
|
||||||
height: 30,
|
height: 30,
|
||||||
),
|
),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
|
||||||
|
],
|
||||||
|
)
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
))),
|
))),
|
||||||
@@ -194,9 +247,7 @@ class _NewActivity extends State<NewActivity> {
|
|||||||
shape: StadiumBorder()
|
shape: StadiumBorder()
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
Navigator.pop(context);
|
||||||
Navigator.pop(context);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
child: Text('Back',
|
child: Text('Back',
|
||||||
style: TextStyle(fontSize: 20))))),
|
style: TextStyle(fontSize: 20))))),
|
||||||
@@ -212,10 +263,6 @@ class _NewActivity extends State<NewActivity> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|
||||||
add_action();
|
add_action();
|
||||||
setState(() {
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
},
|
||||||
child: Text('Add Entry',
|
child: Text('Add Entry',
|
||||||
style: TextStyle(fontSize: 20))))),
|
style: TextStyle(fontSize: 20))))),
|
||||||
@@ -224,14 +271,33 @@ class _NewActivity extends State<NewActivity> {
|
|||||||
])));
|
])));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget QuickTimeButton(text, {Function}){
|
||||||
|
return InkWell(
|
||||||
|
child: Container(
|
||||||
|
padding:EdgeInsets.symmetric(horizontal: 15),
|
||||||
|
height: 30,
|
||||||
|
decoration:BoxDecoration(
|
||||||
|
color: Colors.blueAccent,
|
||||||
|
borderRadius: BorderRadius.circular(50)
|
||||||
|
),
|
||||||
|
child:Align(child: Text(text),alignment: Alignment.center,)
|
||||||
|
),
|
||||||
|
|
||||||
|
onTap: (){
|
||||||
|
Function();
|
||||||
|
setState(() {
|
||||||
|
|
||||||
|
});
|
||||||
|
},);
|
||||||
|
}
|
||||||
|
|
||||||
void add_action() async{
|
void add_action() async{
|
||||||
|
|
||||||
print('adding Task Type : $selectedCat at $startTime - $endTime');
|
print('adding Task Type : $selectedCat at $startTime - $endTime');
|
||||||
bool failed=false;
|
bool failed=false;
|
||||||
await User.UserOperations.addActivity(selectedCat,startTime.toString(), endTime.toString(), onOverlap: (overlapCount){
|
await User.UserOperations.addActivity(selectedCat,startTime.toString(), endTime.toString(),metadata:metadataController.text, onOverlap: (overlapCount){
|
||||||
showAlertDialog(context, 'Error adding activity', 'Cannot add activity between ${dateFormat.format(startTime)} - ${dateFormat.format(endTime)}, $overlapCount activities are already added within this time range');
|
showAlertDialog(context, 'Error adding activity', 'Cannot add activity between ${dateFormat.format(startTime)} - ${dateFormat.format(endTime)}, $overlapCount activities are already added within this time range');
|
||||||
failed=true;
|
failed=true;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!failed)
|
if(!failed)
|
||||||
|
|||||||
47
pubspec.lock
@@ -29,20 +29,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.1"
|
version: "1.3.1"
|
||||||
charts_common:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: charts_common
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.12.0"
|
|
||||||
charts_flutter:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: charts_flutter
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.12.0"
|
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -77,7 +63,7 @@ packages:
|
|||||||
name: device_info_plus
|
name: device_info_plus
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.2.1"
|
version: "3.2.2"
|
||||||
device_info_plus_linux:
|
device_info_plus_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -205,13 +191,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
logging:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: logging
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.2"
|
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -253,14 +232,14 @@ packages:
|
|||||||
name: path_provider_android
|
name: path_provider_android
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.11"
|
version: "2.0.12"
|
||||||
path_provider_ios:
|
path_provider_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_ios
|
name: path_provider_ios
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.7"
|
version: "2.0.8"
|
||||||
path_provider_linux:
|
path_provider_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -330,7 +309,7 @@ packages:
|
|||||||
name: shared_preferences_ios
|
name: shared_preferences_ios
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.10"
|
version: "2.1.0"
|
||||||
shared_preferences_linux:
|
shared_preferences_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -420,6 +399,20 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.0"
|
||||||
|
syncfusion_flutter_charts:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: syncfusion_flutter_charts
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "19.4.53"
|
||||||
|
syncfusion_flutter_core:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: syncfusion_flutter_core
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "19.4.54"
|
||||||
synchronized:
|
synchronized:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -454,7 +447,7 @@ packages:
|
|||||||
name: uuid
|
name: uuid
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.5"
|
version: "3.0.6"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -503,7 +496,7 @@ packages:
|
|||||||
name: win32
|
name: win32
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.10"
|
version: "2.4.1"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -30,11 +30,10 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
|
|
||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
uuid: ^3.0.5
|
uuid: ^3.0.5
|
||||||
wakelock: ^0.6.1+1
|
wakelock: ^0.6.1+1
|
||||||
charts_flutter: ^0.12.0
|
syncfusion_flutter_charts: ^19.4.53
|
||||||
flutter_datetime_picker: ^1.5.1
|
flutter_datetime_picker: ^1.5.1
|
||||||
sqflite: ^2.0.2
|
sqflite: ^2.0.2
|
||||||
intl: ^0.17.0
|
intl: ^0.17.0
|
||||||
|
|||||||