Summary page done

This commit is contained in:
warlock
2022-03-02 09:24:26 +05:30
parent 8c7ea9b86e
commit 4576957b4c
16 changed files with 974 additions and 409 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 B

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 19 KiB

BIN
images/hourglass_base.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
images/hourglass_half.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -1,3 +1,4 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'main.dart';
@@ -6,15 +7,15 @@ import 'Data.dart';
import 'User.dart' as User;
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
class Activities extends StatefulWidget {
const Activities({Key? key}) : super(key: key);
@override
_ActivitiesState createState() => _ActivitiesState();
}
late ProgressDialog progressDialog;
class _ActivitiesState extends State<Activities> {
@override
void initState() {
@@ -28,7 +29,6 @@ class _ActivitiesState extends State<Activities> {
Widget build(BuildContext context) {
progressDialog = ProgressDialog(context: context);
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
Navigator.of(context)
@@ -47,15 +47,29 @@ class _ActivitiesState extends State<Activities> {
SizedBox(width: 10),
Text('Activities')
]),
(selecting)?Row(children: [
InkWell(onTap: (){
(selecting)
? Row(children: [
InkWell(
onTap: () {
DeleteSelectedTasks();
}, child: Icon(Icons.delete,size: 30,)),
SizedBox(width: 20,),
InkWell(onTap: (){setState(() {
},
child: Icon(
Icons.delete,
size: 30,
)),
SizedBox(
width: 20,
),
InkWell(
onTap: () {
setState(() {
selecting = false;
});}, child: Icon(Icons.close,size: 30),)
]) : Container(),
});
},
child: Icon(Icons.close, size: 30),
)
])
: Container(),
],
)),
drawer: navDrawer(context, 2),
@@ -68,10 +82,14 @@ class _ActivitiesState extends State<Activities> {
}
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();
setState(() {});
try{progressDialog.update(value: 100);}catch(e){}
try {
progressDialog.update(value: 100);
} catch (e) {}
}
List<Widget> PrintTasks() {
@@ -79,19 +97,52 @@ class _ActivitiesState extends State<Activities> {
print('Priting cats : ' + User.taskTypes.length.toString());
String lastDate = "";
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) {
String thisDate = dFormat.format(element.startTime);
int thisMinutes= element.endTime.difference(element.startTime).inMinutes;
if(totalMinutes.containsKey(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) {
_tasks.add(DateSeperator(thisDate));
int prodActs = productivtyActs[thisDate] ?? 0;
int unProdActs = unproductivtyActs[thisDate] ?? 0;
_tasks.add(DateSeperator(thisDate, prodActs, unProdActs));
lastDate = thisDate;
}
String name = element.taskType.name;
if (element.taskType.cat == null) {
print('Got some null cat : ${element.taskType.name}');
} 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;
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);
}
}
@@ -99,23 +150,65 @@ class _ActivitiesState extends State<Activities> {
return _tasks;
}
Widget DateSeperator(date){
Widget DateSeperator(date, prodActs, unprodActs) {
double prodPercentage = (prodActs / (prodActs + unprodActs)) * 100;
return Padding(
padding: const EdgeInsets.fromLTRB(10, 20, 10, 0),
child: Column(children: [
child: Column(
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
date,
style: TextStyle(fontSize: 18),
),
Row(children: [
Text(date,style: TextStyle(fontSize: 18),)
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;
Widget ActivityCard(
BuildContext context, String name,DateTime sTime, DateTime eTime, bool productive, Color color, Activity activity) {
Widget ActivityCard(BuildContext context, String name, DateTime sTime,
DateTime eTime, bool productive, Color color, Activity activity,int totalMinutes) {
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);
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: [
// Container(),
(selecting)
@@ -140,40 +233,70 @@ class _ActivitiesState extends State<Activities> {
if (selecting) {
OnItemSelected(activity);
}
setState(() {
});
setState(() {});
},
onLongPress: () {
print('gonna delete');
selecting = !selecting;
selectedActivities = [activity];
setState(() {});
},
child: Container(
padding: EdgeInsets.all(10),
padding: EdgeInsets.all(15),
child: Column(
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(name + " ($timeSpan)",
style: TextStyle(color: Colors.white)),
Text(dateFormat.format(sTime) + " - " + dateFormat.format(eTime)),
Row(children: [
Text(name + " [$timeSpan]",
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.circle,
]),
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)
]),
: Colors.red),
child: Text(
activity.taskType.cat?.name ?? 'n/a'))
// Icon(Icons.circle,
// color: (productive)
// ? Colors.green
// : Colors.red)
])
],
)))),
Container(
margin: EdgeInsets.fromLTRB(15, 0, 15, 10),
height: 2,
color: color)
child:Row(children: [
Expanded(flex:timePercentage ,child: Container(color:color)),
Expanded(flex:100-timePercentage,child:Container())
],)),
]),
),
]);
@@ -188,7 +311,8 @@ class _ActivitiesState extends State<Activities> {
}
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 {
await User.UserOperations.deleteActivity(element, bulk: true);
});
@@ -201,9 +325,10 @@ class _ActivitiesState extends State<Activities> {
setState(() {
progressDialog.update(value: 100);
});
}
}
}
List<Activity> selectedActivities = [];

View File

@@ -152,7 +152,7 @@ class _CategoriesState extends State<Categories> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(name,
style: TextStyle(color: Colors.white)),
),
// Icon(Icons.analytics, color: color, size: 20,),
Icon(Icons.circle,
color: (productive)

View File

@@ -31,15 +31,17 @@ class TaskType{
class Activity{
Activity(this.taskType, this.startTime, this.endTime);
Activity(this.taskType, this.startTime, this.endTime, {this.metadata});
TaskType taskType;
DateTime startTime;
DateTime endTime;
String? metadata;
static String colType = "type";
static String colStartTime = "s_time";
static String colEndTime = "e_time";
static String colMetadata= "metadata";
}
class InitialData{

View File

@@ -85,7 +85,7 @@ class _TasksState extends State<Tasks> {
} else {
Color color = HexColor.fromHex(element.cat?.color ?? '#000000');
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);
}
});
@@ -95,7 +95,7 @@ class _TasksState extends State<Tasks> {
bool selecting = false;
Widget TaskCard(
BuildContext context, String name, bool productive, Color color) {
BuildContext context, String name, bool productive, Color color, String catName) {
return Row(children: [
// Container(),
(selecting)
@@ -140,12 +140,16 @@ class _TasksState extends State<Tasks> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(name,
style: TextStyle(color: Colors.white)),
),
// Icon(Icons.analytics, color: color, size: 20,),
Icon(Icons.circle,
color: (productive)
? Colors.green
: Colors.red)
Container(
padding: EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: (productive) ? Colors.green : Colors.red
),
child:Text(catName)
)
]),
],
)))),

View File

@@ -61,7 +61,7 @@ Future<void> initUserData() async {
print('Going offline mode.');
}
}
bool userDataInitiated =false;
Future<void> refreshUserData() async{
ShowProgress("Loading data");
// categories= await GetCategories(true);
@@ -70,6 +70,7 @@ Future<void> refreshUserData() async{
await updateCatsList();
await updateTasksList();
await updateActList();
userDataInitiated=true;
HideProgress();
}
@@ -122,7 +123,7 @@ void onCacheDatabaseCreate(Database db, int newVersion) async {
await db.execute(TaskTableSQL);
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))';
// print(ActivityTableSQL);
await db.execute(ActivityTableSQL);
@@ -328,7 +329,7 @@ Future<List<Activity>> GetActivities(bool forceOffline) async{
List<Activity> _activities = [];
if(offline || forceOffline){
//Retreive from cacheDB
print('offline, refreshing activities');
}else{
//Check if server got updated, If not go for cache
var android_id = await Settings.UUID();
@@ -359,14 +360,15 @@ Future<List<Activity>> GetActivities(bool forceOffline) async{
String? type = element[Activity.colType].toString();
String? startTime = element[Activity.colStartTime].toString();
String? endTime = element[Activity.colEndTime].toString();
String? metadata = element[Activity.colMetadata].toString();
TaskType? taskType = await getTaskFromId(type);
if(type==null || startTime==null || endTime==null || taskType==null){
print("Something is null!");
print("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}");
print("Something is null!\ntype:${type==null}, startTime:${startTime==null}, eTime:${endTime==null}, taskType${taskType==null}");
print("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}, metadata:${metadata}");
continue;
}
print("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}");
_activities.add(Activity(taskType, DateTime.parse(startTime), DateTime.parse(endTime)));
print("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}, metadata:${metadata}");
_activities.add(Activity(taskType, DateTime.parse(startTime), DateTime.parse(endTime), metadata: metadata));
}
activities = _activities;
return activities;
@@ -395,8 +397,8 @@ Future<void> UpdateActivitiesFromServer() async{
Map<String, dynamic> cat = jsonDecode(value);
print(cat);
await cacheDb.rawInsert(
"INSERT OR REPLACE INTO Activities (${Activity.colType}, ${Activity.colStartTime}, ${Activity.colEndTime}) "
"VALUES ('${cat['task_id']}', '${cat['sTime']}','${cat['eTime']}') ");
"INSERT OR REPLACE INTO Activities (${Activity.colType}, ${Activity.colStartTime}, ${Activity.colEndTime}, ${Activity.colMetadata}) "
"VALUES ('${cat['task_id']}', '${cat['sTime']}','${cat['eTime']}', '${cat['metadata']}') ");
}
}else{
print("No activities for now");
@@ -410,13 +412,15 @@ Future<void> UpdateActivitiesFromServer() async{
Future<TaskType?> getTaskFromId(String taskId) async{
// await GetTaskTypes(false);
TaskType? cat = null;
taskTypes.forEach((element) async{
for (var element in taskTypes){
if(element.id == taskId){
cat= element;
cat?.cat = await getCatFromId((cat?.category ?? ''));
}
});
}
if(cat==null){
print('Got null tasktype for ${taskId} after searching on ${taskTypes.length}');
}
return cat;
}
@@ -424,11 +428,11 @@ Future<TaskType?> getTaskFromId(String taskId) async{
Future<Category?> getCatFromId(String catId) async{
// await GetTaskTypes(false);
Category? cat = null;
categories.forEach((element) {
for (var element in categories) {
if(element.category_id == catId){
cat= element;
}
});
}
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
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')))"));
@@ -533,8 +537,13 @@ class UserOperations{
'device_id': await Settings.UUID(),
'type' : username+type,
'sTime': sTime,
'eTime':eTime
'eTime':eTime,
'metadata': metadata
};
if(metadata.length > 0){
}
//Add Query
Map<String,Object> query = {
Queries.colLink: 'add_activity',
@@ -547,12 +556,13 @@ class UserOperations{
//update Cache
Map<String,Object> data = {
Activity.colType: type,
Activity.colType: username+type,
Activity.colStartTime: sTime,
Activity.colEndTime: eTime
Activity.colEndTime: eTime,
Activity.colMetadata: metadata
};
await cacheDb.insert('Activities', data);
await GetActivities(true);
activities= await GetActivities(false);
if(!bulk){
//Add to server and refresh Cache
await executeQueries();
@@ -688,10 +698,10 @@ class UserOperations{
}
void ShowProgress(msg){
try{progressDialog?.show(max: 100, msg: msg);}catch(e){}
//try{progressDialog?.show(max: 100, msg: msg);}catch(e){}
}
void HideProgress(){
try{progressDialog?.update(value: 100);}catch(e){}
// try{progressDialog?.update(value: 100);}catch(e){}
}

View File

@@ -1,25 +1,28 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:tasktracker/Categories.dart';
import 'package:tasktracker/Welcome.dart';
import 'package:tasktracker/splash.dart';
import 'package:wakelock/wakelock.dart';
import 'package:charts_flutter/flutter.dart' as charts;
import 'Data.dart';
import 'NewTask.dart';
import 'newActivity.dart';
import 'Tasks.dart';
import 'Activities.dart';
import 'User.dart' as User;
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
late ProgressDialog progressDialog;
showAlertDialog(BuildContext context, String title, String message) {
// set up the button
Widget okButton = TextButton(
child: Text("OK"),
onPressed: () { Navigator.of(context).pop(); },
onPressed: () {
Navigator.of(context).pop();
},
);
// set up the AlertDialog
@@ -57,26 +60,6 @@ extension HexColor on Color {
'${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() {
//Wakelock.enable(); // or Wakelock.toggle(on: true);
runApp(const MyApp());
@@ -89,11 +72,7 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
accentColor: Colors.redAccent,
brightness: Brightness.dark,
primaryColor: Colors.amber,
fontFamily: 'Noto-Sans'),
theme: ThemeData(accentColor: Colors.redAccent, brightness: Brightness.dark, primaryColor: Colors.amber, fontFamily: 'Noto-Sans'),
//home: const MyHomePage(),
initialRoute: '/splash',
routes: {
@@ -103,11 +82,41 @@ class MyApp extends StatelessWidget {
'/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 {
const MyHomePage({Key? key}) : super(key: key);
@@ -116,177 +125,467 @@ class MyHomePage extends StatefulWidget {
}
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
void initState() {
// TODO: implement initState
super.initState();
User.refreshUserData().then((val) => LoadStats());
// showOfflineSnack();
LoadStats();
// progressDialog = ProgressDialog(context: context);
// User.progressDialog=progressDialog;
}
showOfflineSnack();
progressDialog = ProgressDialog(context: context);
User.progressDialog=progressDialog;
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));
if (User.offline) {
const SnackBar offlineSnack = SnackBar(content: Text('Offline'),duration: Duration(seconds: 100),);
ScaffoldMessenger.of(context).showSnackBar(offlineSnack);
const SnackBar offlineSnack = SnackBar(
content: Text('Offline'),
duration: Duration(seconds: 100),
);
// ScaffoldMessenger.of(context).showSnackBar(offlineSnack);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton.extended(onPressed: (){
Navigator.of(context).push(MaterialPageRoute(builder: (context)=> NewActivity()));
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewActivity())).then((value) => {User.refreshUserData().then((va) => LoadStats())});
},
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')])),
drawer: navDrawer(context, 0),
body: SafeArea(
child: Container(
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
(false)
? Container(
padding: EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
Text("Good\nMorning!", style: TextStyle(fontSize: 23, fontStyle: FontStyle.italic)),
Text(
"12%",
style: TextStyle(fontSize: 30),
),
Column(
children: [
Text(DateFormat("yy - MM-dd").format(DateTime.now())),
Text(DateFormat("HH:mm").format(DateTime.now()), style: TextStyle(fontSize: 40)),
],
)
],
),
)
: Container(),
Container(
height: 300,
padding: EdgeInsets.all(20),
padding: EdgeInsets.all(10),
child: Card(
elevation: 8,
shadowColor: Colors.blueGrey,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 20),
child: Column(
children: [
Row(
children: [
SizedBox(
width: 10,
),
Text("Productivity", style: TextStyle(color: Colors.green, fontWeight: FontWeight.bold)),
],
),
Divider(),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Row(
children: [
Text("Today : "),
Text("${(productivityData.length > 0) ? productivityData[0].productivity.toStringAsFixed(1) : 'n/a'}%",
style: TextStyle(
fontSize: 20,
color: (productivityData.length > 1)
? ((productivityData[0].productivity > productivityData[1].productivity) ? Colors.lightGreenAccent : Colors.red)
: Colors.white))
],
),
Row(
children: [
Text("Yesterday : "),
Text("${(productivityData.length > 1) ? productivityData[1].productivity.toStringAsFixed(1) : 'n/a'}%", style: TextStyle(fontSize: 18))
],
),
],
),
Expanded(
child: SfCartesianChart(
// Initialize category axis
primaryXAxis: CategoryAxis(),
series: <LineSeries<ProductivityMapData, String>>[
LineSeries<ProductivityMapData, String>(
// Bind data source
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: Column(
child: (!days.isEmpty)
? Column(
children: [
cardTitle('Daily Average'),
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: charts.BarChart(
series,
animate: true,
barRendererDecorator:
new charts.BarLabelDecorator(
labelPosition:
charts.BarLabelPosition.inside,
labelPadding: 10,
labelAnchor:
charts.BarLabelAnchor.middle),
))
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: 300,
padding: EdgeInsets.all(20),
height: 450,
padding: EdgeInsets.all(10),
child: Card(
elevation: 8,
shadowColor: Colors.green,
shadowColor: Colors.blueGrey,
child: Padding(
padding: EdgeInsets.all(8),
child: Column(
children: [
cardTitle('Weekly Average'),
Expanded(
child: charts.BarChart(
series,
animate: true,
barRendererDecorator:
new charts.BarLabelDecorator(
labelPosition:
charts.BarLabelPosition.inside,
labelPadding: 10,
labelAnchor:
charts.BarLabelAnchor.middle),
))
],
))))
],
),
),
));
}
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;
}
Widget cardTitle(String title) {
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(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(padding: EdgeInsets.all(20),child:Text(title,
style: TextStyle(fontWeight: FontWeight.bold))),
MaterialButton(onPressed: (){},child:moreButton())]);
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 moreButton() {
return MaterialButton(
onPressed: (){
},
onPressed: () {},
color: Colors.green,
child: Row(
children: [
Text('More'),Icon(Icons.keyboard_arrow_right)
],
children: [Text('More'), Icon(Icons.keyboard_arrow_right)],
));
}
class PopulationData {
String name;
int value;
charts.Color barColor;
PopulationData(
{required this.name, required this.value, required this.barColor});
}
Drawer navDrawer(BuildContext context, int pageIndex) {
return Drawer(
child: ListView(
children: [
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,),
])
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;}
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('/');
},
),
// 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;}
if (pageIndex == 2) {
return;
}
Navigator.of(context).pushReplacementNamed('/Activities');
},
),
@@ -295,7 +594,9 @@ Drawer navDrawer(BuildContext context, int pageIndex){
title: Text('Task Types'),
leading: Icon(Icons.task, color: Theme.of(context).primaryColor),
onTap: () {
if(pageIndex==3){return;}
if (pageIndex == 3) {
return;
}
Navigator.of(context).pushReplacementNamed('/Tasks');
},
),
@@ -304,7 +605,9 @@ Drawer navDrawer(BuildContext context, int pageIndex){
title: Text('Categories'),
leading: Icon(Icons.account_tree_outlined, color: Theme.of(context).primaryColor),
onTap: () {
if(pageIndex==4){return;}
if (pageIndex == 4) {
return;
}
Navigator.of(context).pushReplacementNamed('/Categories');
},
),
@@ -313,18 +616,81 @@ Drawer navDrawer(BuildContext context, int pageIndex){
selected: (pageIndex == 5),
title: Text('Settings'),
leading: Icon(Icons.settings, color: Colors.blueGrey),
onTap: () {
},
onTap: () {},
),
ListTile(
selected: (pageIndex == 6),
title: Text('About'),
leading: Icon(Icons.help_outline_outlined),
onTap: () {
},
onTap: () {},
),
],
));
}
class MyPlayerBar extends CustomPainter {
MyPlayerBar(this.max, this.value, {this.background = Colors.lightBlue, this.fill = Colors.blue});
Color background = Colors.lightBlue;
Color fill = Colors.blue;
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;
}
class CatMapData {
CatMapData(this.name, this.time, this.color);
final String name;
final int time;
final Color color;
}
class ProductivityMapData {
ProductivityMapData(this.day, this.productivity);
final String day;
final double productivity;
}
class TaskTypeMapData {
TaskTypeMapData(this.task, this.time, this.color);
final Color color;
final String task;
final int time;
}
String MinutesToTimeString(minutes) {
int hours = (minutes / 60).floor();
int mins = minutes % 60;
String str = "";
if (hours > 0) {
str += hours.toString() + "h";
}
if (mins > 0) {
str += ((hours > 0) ? " " : "") + mins.toString() + "m";
}
return str;
}

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
import 'package:intl/intl.dart';
import 'User.dart' as User;
@@ -31,6 +32,7 @@ class _NewActivity extends State<NewActivity> {
DateTime startTime = DateTime.now();
DateTime endTime = DateTime.now().add(Duration(minutes: 30));
TextEditingController metadataController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -50,6 +52,7 @@ class _NewActivity extends State<NewActivity> {
Container(
padding: EdgeInsets.all(10),
child: Text('Task')),
Container(
padding: EdgeInsets.symmetric(
horizontal: 12, vertical: 1),
@@ -78,6 +81,25 @@ class _NewActivity extends State<NewActivity> {
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(
child: Divider(
height: 30,
@@ -85,6 +107,16 @@ class _NewActivity extends State<NewActivity> {
Container(
padding: EdgeInsets.all(10),
child: Text('Start Time')),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
QuickTimeButton('Last', Function: (){
if(User.activities.length > 0) {
startTime= User.activities[0].endTime;
}
})
,
Container(
padding: EdgeInsets.symmetric(
horizontal: 12, vertical: 1),
@@ -120,12 +152,22 @@ class _NewActivity extends State<NewActivity> {
dateFormat.format(startTime),
style: TextStyle(
color: Colors.blue)))),
QuickTimeButton('Now', Function: (){
startTime = DateTime.now();
})
],
),
SizedBox(
height: 10,
),
Container(
padding: EdgeInsets.all(10),
child: Text('Ended Time')),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(width: 60,),
Container(
padding: EdgeInsets.symmetric(
horizontal: 12, vertical: 1),
@@ -161,6 +203,11 @@ class _NewActivity extends State<NewActivity> {
child: Text(dateFormat.format(endTime),
style: TextStyle(
color: Colors.blue)))),
QuickTimeButton('Now', Function: (){
endTime = DateTime.now();
})
],
),
SizedBox(
height: 30,
),
@@ -173,6 +220,12 @@ class _NewActivity extends State<NewActivity> {
Divider(
height: 30,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
],
)
]),
],
))),
@@ -194,9 +247,7 @@ class _NewActivity extends State<NewActivity> {
shape: StadiumBorder()
),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
child: Text('Back',
style: TextStyle(fontSize: 20))))),
@@ -212,10 +263,6 @@ class _NewActivity extends State<NewActivity> {
onPressed: () {
add_action();
setState(() {
});
},
child: Text('Add Entry',
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{
print('adding Task Type : $selectedCat at $startTime - $endTime');
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');
failed=true;
});
if(!failed)

View File

@@ -29,20 +29,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
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:
dependency: transitive
description:
@@ -77,7 +63,7 @@ packages:
name: device_info_plus
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.1"
version: "3.2.2"
device_info_plus_linux:
dependency: transitive
description:
@@ -205,13 +191,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
logging:
dependency: transitive
description:
name: logging
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
matcher:
dependency: transitive
description:
@@ -253,14 +232,14 @@ packages:
name: path_provider_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.11"
version: "2.0.12"
path_provider_ios:
dependency: transitive
description:
name: path_provider_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.7"
version: "2.0.8"
path_provider_linux:
dependency: transitive
description:
@@ -330,7 +309,7 @@ packages:
name: shared_preferences_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.10"
version: "2.1.0"
shared_preferences_linux:
dependency: transitive
description:
@@ -420,6 +399,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
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:
dependency: transitive
description:
@@ -454,7 +447,7 @@ packages:
name: uuid
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.5"
version: "3.0.6"
vector_math:
dependency: transitive
description:
@@ -503,7 +496,7 @@ packages:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.10"
version: "2.4.1"
xdg_directories:
dependency: transitive
description:

View File

@@ -30,11 +30,10 @@ dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
uuid: ^3.0.5
wakelock: ^0.6.1+1
charts_flutter: ^0.12.0
syncfusion_flutter_charts: ^19.4.53
flutter_datetime_picker: ^1.5.1
sqflite: ^2.0.2
intl: ^0.17.0