Todo basics added

This commit is contained in:
Sewmina
2022-03-31 15:12:31 +05:30
parent ead2c466d1
commit 62ae8bad01
12 changed files with 1698 additions and 830 deletions

View File

@@ -8,6 +8,7 @@ import 'newActivity.dart';
import 'Data.dart'; import 'Data.dart';
import 'User.dart' as User; import 'User.dart' as User;
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
class Activities extends StatefulWidget { class Activities extends StatefulWidget {
const Activities({Key? key}) : super(key: key); const Activities({Key? key}) : super(key: key);
@@ -15,8 +16,6 @@ class Activities extends StatefulWidget {
_ActivitiesState createState() => _ActivitiesState(); _ActivitiesState createState() => _ActivitiesState();
} }
class _ActivitiesState extends State<Activities> { class _ActivitiesState extends State<Activities> {
//late ProgressDialog progressDialog; //late ProgressDialog progressDialog;
TextEditingController searchController = TextEditingController(); TextEditingController searchController = TextEditingController();
@@ -26,13 +25,12 @@ class _ActivitiesState extends State<Activities> {
void _onFocusChange() { void _onFocusChange() {
print("FOCUS CHANGED! : ${_focus.hasFocus}"); print("FOCUS CHANGED! : ${_focus.hasFocus}");
if(!_focus.hasFocus){ if (!_focus.hasFocus) {
searching=false; searching = false;
setState(() { setState(() {});
}
}
});
}
}
var refreshSub; var refreshSub;
@override @override
void initState() { void initState() {
@@ -40,10 +38,8 @@ class _ActivitiesState extends State<Activities> {
super.initState(); super.initState();
_focus.addListener(_onFocusChange); _focus.addListener(_onFocusChange);
refreshSub = User.refreshStream.stream.listen((event) { refreshSub = User.refreshStream.stream.listen((event) {
if(!event){ if (!event) {
setState(() { setState(() {});
});
} }
}); });
//UpdateList(); //UpdateList();
@@ -58,6 +54,7 @@ class _ActivitiesState extends State<Activities> {
_focus.dispose(); _focus.dispose();
refreshSub?.closeStream(); refreshSub?.closeStream();
} }
void UpdateList() async { void UpdateList() async {
try { try {
//progressDialog.show(max: 100, msg: 'Loading Activities'); //progressDialog.show(max: 100, msg: 'Loading Activities');
@@ -68,6 +65,7 @@ class _ActivitiesState extends State<Activities> {
// progressDialog.update(value: 100); // progressDialog.update(value: 100);
} catch (e) {} } catch (e) {}
} }
Map<String, ActivityListDateGroup> activitiesGroups = <String, ActivityListDateGroup>{}; Map<String, ActivityListDateGroup> activitiesGroups = <String, ActivityListDateGroup>{};
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -91,26 +89,34 @@ class _ActivitiesState extends State<Activities> {
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: [ children: [
Expanded( Expanded(
child: TextField(onChanged: (text){setState(() { child: TextField(
onChanged: (text) {
});},controller: searchController, focusNode: _focus, decoration: InputDecoration( setState(() {});
},
controller: searchController,
focusNode: _focus,
decoration: InputDecoration(
filled: true, filled: true,
),), ),
),
), ),
InkWell( InkWell(
onTap: (){searching=false; onTap: () {
searching = false;
searchController.clear(); searchController.clear();
setState(() { setState(() {});
},
});},
child: Container( child: Container(
margin: EdgeInsets.all( 10), margin: EdgeInsets.all(10),
child: Icon(Icons.cancel), child: Icon(Icons.cancel),
), ),
) )
], ],
), ),
Text('searched time : ${Main.MinutesToTimeString(searchTime)}',style: TextStyle(fontSize: 15),) Text(
'searched time : ${Main.MinutesToTimeString(searchTime)}',
style: TextStyle(fontSize: 15),
)
], ],
) )
: Row( : Row(
@@ -131,14 +137,13 @@ class _ActivitiesState extends State<Activities> {
size: 30, size: 30,
), ),
)), )),
InkWell( InkWell(
onTap: () { onTap: () {
setState(() { setState(() {
selecting = false; selecting = false;
}); });
}, },
child: Container(margin:EdgeInsets.all(10),child: Icon(Icons.close, size: 30)), child: Container(margin: EdgeInsets.all(10), child: Icon(Icons.close, size: 30)),
) )
]) ])
: Row( : Row(
@@ -147,9 +152,7 @@ class _ActivitiesState extends State<Activities> {
onTap: () { onTap: () {
searching = true; searching = true;
_focus.requestFocus(); _focus.requestFocus();
setState(() { setState(() {});
});
}, },
child: Container( child: Container(
margin: EdgeInsets.all(10), margin: EdgeInsets.all(10),
@@ -161,11 +164,9 @@ class _ActivitiesState extends State<Activities> {
InkWell( InkWell(
onTap: () { onTap: () {
UpdateList(); UpdateList();
setState(() { setState(() {});
});
}, },
child: Container(margin: EdgeInsets.all(10),child: Icon(Icons.refresh, size: 30)), child: Container(margin: EdgeInsets.all(10), child: Icon(Icons.refresh, size: 30)),
) )
], ],
), ),
@@ -177,14 +178,13 @@ class _ActivitiesState extends State<Activities> {
child: ScrollablePositionedList.builder( child: ScrollablePositionedList.builder(
itemScrollController: scrollController, itemScrollController: scrollController,
itemCount: activitiesGroups.length, itemCount: activitiesGroups.length,
itemBuilder: (context, index){ itemBuilder: (context, index) {
// return activities[index]; // return activities[index];
return StickyHeader( return StickyHeader(
header: activitiesGroups.values.toList()[index].dateSeperator,
header:activitiesGroups.values.toList()[index].dateSeperator, content: Column(
content:Column(children: activitiesGroups.values.toList()[index].activities,) children: activitiesGroups.values.toList()[index].activities,
); ));
}) })
// SingleChildScrollView( // SingleChildScrollView(
// child: Column( // child: Column(
@@ -192,13 +192,13 @@ class _ActivitiesState extends State<Activities> {
// )) // ))
)); ));
} }
DateFormat dFormat = DateFormat("yyyy-MM-dd"); DateFormat dFormat = DateFormat("yyyy-MM-dd");
ItemScrollController scrollController = ItemScrollController(); ItemScrollController scrollController = ItemScrollController();
ScrollController controller = ScrollController(); ScrollController controller = ScrollController();
int searchTime = 0; int searchTime = 0;
Map<String,ActivityListDateGroup> PrintTasks() { Map<String, ActivityListDateGroup> PrintTasks() {
Map<String, ActivityListDateGroup> _tasks = <String, ActivityListDateGroup>{};
Map<String,ActivityListDateGroup> _tasks = <String,ActivityListDateGroup>{};
print('Priting cats : ' + User.taskTypes.length.toString()); print('Priting cats : ' + User.taskTypes.length.toString());
String lastDate = ""; String lastDate = "";
@@ -233,24 +233,23 @@ class _ActivitiesState extends State<Activities> {
} }
print(productivtyActs); print(productivtyActs);
//for (var element in User.activities) { //for (var element in User.activities) {
searchTime=0; searchTime = 0;
for(int i =0; i < User.activities.length; i++){ for (int i = 0; i < User.activities.length; i++) {
Activity element =User.activities[i]; Activity element = User.activities[i];
if(searching){ if (searching) {
bool matchMetadata = element.metadata!.toLowerCase().contains(searchController.text.toLowerCase()); bool matchMetadata = element.metadata!.toLowerCase().contains(searchController.text.toLowerCase());
bool matchTaskType=element.taskType.name.toLowerCase().contains(searchController.text.toLowerCase()); bool matchTaskType = element.taskType.name.toLowerCase().contains(searchController.text.toLowerCase());
bool matchCategory = element.taskType.cat!.name.toLowerCase().contains(searchController.text.toLowerCase()); bool matchCategory = element.taskType.cat!.name.toLowerCase().contains(searchController.text.toLowerCase());
if(matchMetadata || matchTaskType || matchCategory){ if (matchMetadata || matchTaskType || matchCategory) {
//Good to go //Good to go
searchTime += element.endTime.difference(element.startTime).inMinutes; searchTime += element.endTime.difference(element.startTime).inMinutes;
}else{ } else {
continue; continue;
} }
} }
String thisDate = dFormat.format(element.startTime); String thisDate = dFormat.format(element.startTime);
if (thisDate != lastDate) { if (thisDate != lastDate) {
int prodActs = productivtyActs[thisDate] ?? 0; int prodActs = productivtyActs[thisDate] ?? 0;
int unProdActs = unproductivtyActs[thisDate] ?? 0; int unProdActs = unproductivtyActs[thisDate] ?? 0;
@@ -272,10 +271,10 @@ class _ActivitiesState extends State<Activities> {
_tasks[thisDate]!.activities.add(task); _tasks[thisDate]!.activities.add(task);
} }
//Check for gaps //Check for gaps
if(i < User.activities.length-1){ if (i < User.activities.length - 1) {
int gap = User.activities[i].trueStartTime.difference(User.activities[i+1].trueEndTime).inMinutes; int gap = User.activities[i].trueStartTime.difference(User.activities[i + 1].trueEndTime).inMinutes;
if(gap > 10) { if (gap > 10) {
Widget addGap = timeGap(User.activities[i].trueStartTime, User.activities[i+1].trueEndTime); Widget addGap = timeGap(User.activities[i].trueStartTime, User.activities[i + 1].trueEndTime);
//_tasks.values.toList()[_tasks.length-1].add(addGap); //_tasks.values.toList()[_tasks.length-1].add(addGap);
_tasks[thisDate]!.activities.add(addGap); _tasks[thisDate]!.activities.add(addGap);
@@ -286,23 +285,25 @@ class _ActivitiesState extends State<Activities> {
return _tasks; return _tasks;
} }
Widget timeGap(DateTime sTime, DateTime eTime){ Widget timeGap(DateTime sTime, DateTime eTime) {
DateFormat dateFormat = DateFormat("HH:mm"); DateFormat dateFormat = DateFormat("HH:mm");
String gap = Main.MinutesToTimeString(sTime.difference(eTime).inMinutes); String gap = Main.MinutesToTimeString(sTime.difference(eTime).inMinutes);
return Row( return Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: [
Container(padding: EdgeInsets.fromLTRB(10, 0, 5, 0), child: Column(
mainAxisSize: MainAxisSize.max,mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Container(
padding: EdgeInsets.fromLTRB(10, 0, 5, 0),
child: Column(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: [
// Text(dateFormat.format(activity.endTime)), // Text(dateFormat.format(activity.endTime)),
SizedBox(width: 1, height: 30, child: Container(color: Colors.white)), SizedBox(width: 1, height: 30, child: Container(color: Colors.white)),
Text(dateFormat.format(eTime))])), Text(dateFormat.format(eTime))
])),
Expanded( Expanded(
child: InkWell( child: InkWell(
onTap: (){ onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewActivity(sTime: eTime,eTime: sTime))).then((value) => UpdateList()); Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => NewActivity(sTime: eTime, eTime: sTime)))
.then((value) => UpdateList());
}, },
child: Card( child: Card(
child: Row( child: Row(
@@ -315,43 +316,37 @@ class _ActivitiesState extends State<Activities> {
child: Text('Untracked period $gap'), child: Text('Untracked period $gap'),
), ),
Row( Row(
children: [ children: [Icon(Icons.add, size: 30), Text("Add Activity")],
Icon(Icons.add,size:30),
Text("Add Activity")
],
), ),
], ],
) )),
),
), ),
), ),
], ],
); );
} }
void OnJumpToDate(date){ void OnJumpToDate(date) {
int itemId = 0; int itemId = 0;
List<String> keys = activitiesGroups.keys.toList(); List<String> keys = activitiesGroups.keys.toList();
List<ActivityListDateGroup> values = activitiesGroups.values.toList(); List<ActivityListDateGroup> values = activitiesGroups.values.toList();
for(int i =0; i < activitiesGroups.length; i++){ for (int i = 0; i < activitiesGroups.length; i++) {
if (keys[i] == dFormat.format(date)) {
if(keys[i] == dFormat.format(date)){
break; break;
} }
itemId++; itemId++;
// itemId+= values[i].activities.length; // itemId+= values[i].activities.length;
} }
scrollController.scrollTo(index: itemId, duration: Duration(seconds: 1),curve: Curves.fastOutSlowIn); scrollController.scrollTo(index: itemId, duration: Duration(seconds: 1), curve: Curves.fastOutSlowIn);
} }
Widget DateSeperator(date, prodActs, unprodActs,{Function? onTap}) { Widget DateSeperator(date, prodActs, unprodActs, {Function? onTap}) {
// double prodPercentage = (prodActs / (prodActs + unprodActs)) * 100; // double prodPercentage = (prodActs / (prodActs + unprodActs)) * 100;
return FutureBuilder( return FutureBuilder(
future: Settings.getUntrackedUnproductive(), future: Settings.getUntrackedUnproductive(),
builder: (context, snapshot) { builder: (context, snapshot) {
double prodPercentage = (User.ParseBool(snapshot.data))? ((prodActs / 1440) * 100) : ((prodActs / unprodActs) * 100); double prodPercentage = (User.ParseBool(snapshot.data)) ? ((prodActs / 1440) * 100) : ((prodActs / unprodActs) * 100);
return Container( return Container(
color: Color(0xFF333333), color: Color(0xFF333333),
padding: const EdgeInsets.fromLTRB(0, 10, 10, 10), padding: const EdgeInsets.fromLTRB(0, 10, 10, 10),
@@ -363,10 +358,10 @@ class _ActivitiesState extends State<Activities> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
InkWell( InkWell(
onTap: (){ onTap: () {
DatePicker.showDatePicker(context, DatePicker.showDatePicker(context,
showTitleActions: true, showTitleActions: true,
minTime: User.activities[User.activities.length-1].startTime, minTime: User.activities[User.activities.length - 1].startTime,
maxTime: User.activities[0].startTime, maxTime: User.activities[0].startTime,
theme: DatePickerTheme(), onChanged: (date) { theme: DatePickerTheme(), onChanged: (date) {
// print('change $date'); // print('change $date');
@@ -374,7 +369,9 @@ class _ActivitiesState extends State<Activities> {
}, },
child: Row( child: Row(
children: [ children: [
SizedBox(width: 15,), SizedBox(
width: 15,
),
Icon(Icons.circle), Icon(Icons.circle),
SizedBox( SizedBox(
width: 10, width: 10,
@@ -390,10 +387,18 @@ class _ActivitiesState extends State<Activities> {
children: [ children: [
Row( Row(
children: [ children: [
if(prodPercentage < 35)Text(Main.MinutesToTimeString(prodActs),), if (prodPercentage < 35)
Text(
Main.MinutesToTimeString(prodActs),
),
Container( Container(
child: Align( child: Align(
child: (prodPercentage >= 35) ?FittedBox(child: Text(Main.MinutesToTimeString(prodActs),)) : Container(), child: (prodPercentage >= 35)
? FittedBox(
child: Text(
Main.MinutesToTimeString(prodActs),
))
: Container(),
alignment: Alignment.center, alignment: Alignment.center,
), ),
width: (prodPercentage) * 1, width: (prodPercentage) * 1,
@@ -402,20 +407,21 @@ class _ActivitiesState extends State<Activities> {
), ),
Container( Container(
child: Align( child: Align(
child: (prodPercentage < 35) ?Text(Main.MinutesToTimeString(unprodActs)) :Container(), child: (prodPercentage < 35) ? Text(Main.MinutesToTimeString(unprodActs)) : Container(),
alignment: Alignment.center, alignment: Alignment.center,
), ),
width: (100 - prodPercentage) * 1, width: (100 - prodPercentage) * 1,
height: 20, height: 20,
decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.horizontal(right: Radius.circular(10))), decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.horizontal(right: Radius.circular(10))),
), ),
if(prodPercentage >= 35)Text(Main.MinutesToTimeString(unprodActs)) if (prodPercentage >= 35) Text(Main.MinutesToTimeString(unprodActs))
], ],
), ),
SizedBox( SizedBox(
width: 10, width: 10,
), ),
Text(prodPercentage.toStringAsFixed(1) + "%", style: TextStyle(color: Colors.green, fontWeight: FontWeight.bold, fontSize: 20)) Text(prodPercentage.toStringAsFixed(1) + "%",
style: TextStyle(color: Colors.green, fontWeight: FontWeight.bold, fontSize: 20))
], ],
) )
// CustomPaint( // CustomPaint(
@@ -436,20 +442,22 @@ class _ActivitiesState extends State<Activities> {
], ],
), ),
); );
} });
);
} }
bool selecting = false; bool selecting = false;
Widget ActivityCard(BuildContext context, String name, DateTime sTime, DateTime eTime, bool productive, Color color, Activity activity, int totalMinutes) { Widget ActivityCard(
BuildContext context, String name, DateTime sTime, 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 thisMinutes = (activity.endTime.difference(activity.startTime).inMinutes);
int timePercentage = ((thisMinutes / totalMinutes) * 100).toInt(); int timePercentage = ((thisMinutes / totalMinutes) * 100).toInt();
// print("$thisMinutes / $totalMinutes"); // print("$thisMinutes / $totalMinutes");
bool containsMetadata = ((activity.metadata ?? 'null') != 'null') && ((activity.metadata ?? '').isNotEmpty); bool containsMetadata = ((activity.metadata ?? 'null') != 'null') && ((activity.metadata ?? '').isNotEmpty);
bool containsStepData = (containsMetadata && activity.metadata!.contains('[') && activity.metadata!.contains(']'));
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)
@@ -460,8 +468,11 @@ class _ActivitiesState extends State<Activities> {
OnItemSelected(activity); OnItemSelected(activity);
setState(() {}); setState(() {});
}) })
: Container(padding: EdgeInsets.fromLTRB(10, 0, 5, 0), child: Column( : Container(
mainAxisSize: MainAxisSize.max,mainAxisAlignment: MainAxisAlignment.center, padding: EdgeInsets.fromLTRB(10, 0, 5, 0),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
// Text(dateFormat.format(activity.endTime)), // Text(dateFormat.format(activity.endTime)),
SizedBox(width: 1, height: 100, child: Container(color: Colors.white)), SizedBox(width: 1, height: 100, child: Container(color: Colors.white)),
@@ -497,19 +508,20 @@ class _ActivitiesState extends State<Activities> {
children: [ children: [
Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.start, children: [ Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.start, children: [
Text(name + " [$timeSpan]", style: TextStyle(fontSize: 17)), Text(name + " [$timeSpan]", style: TextStyle(fontSize: 17)),
if (containsMetadata)Row(mainAxisAlignment:MainAxisAlignment.start,mainAxisSize: MainAxisSize.max,children: [ if (containsMetadata)
Row(mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.max, children: [
Icon( Icon(
Icons.arrow_forward_outlined, Icons.arrow_forward_outlined,
size: 20, size: 20,
), ),
SizedBox( SizedBox(
width: MediaQuery.of(context).size.width/3, width: MediaQuery.of(context).size.width / 3,
child: Text( child: Text(
activity.metadata ?? '', (containsStepData)
? activity.metadata!.substring(activity.metadata!.indexOf(']') + 1)
: (activity.metadata ?? ''),
), ),
), ),
]), ]),
// Icon(Icons.analytics, color: color, size: 20,), // Icon(Icons.analytics, color: color, size: 20,),
]), ]),
@@ -523,14 +535,29 @@ class _ActivitiesState extends State<Activities> {
), ),
Row( Row(
children: [ children: [
(activity.taskType.relatedProject!= null) ?Container( (activity.taskType.relatedProject != null)
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2), ? Row(
decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.black26), children: [
child: Text(activity.taskType.relatedProject!.name ?? 'n/a')) : Container(), if (containsStepData)
SizedBox(width: 10,),
Container( Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2), padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: (productive) ? Colors.green : Colors.red), decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.black26),
child: Text(activity.metadata!.substring(1, activity.metadata!.indexOf(']')) ?? 'n/a')),
SizedBox(width: 8 ,),
Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.black26),
child: Text(activity.taskType.relatedProject!.name ?? 'n/a')),
],
)
: Container(),
SizedBox(
width: 10,
),
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')), child: Text(activity.taskType.cat?.name ?? 'n/a')),
], ],
) )
@@ -540,7 +567,8 @@ class _ActivitiesState extends State<Activities> {
// : Colors.red) // : Colors.red)
]) ])
], ],
)))), ))
)),
), ),
Container( Container(
margin: EdgeInsets.fromLTRB(15, 0, 15, 10), margin: EdgeInsets.fromLTRB(15, 0, 15, 10),
@@ -550,14 +578,25 @@ class _ActivitiesState extends State<Activities> {
)), )),
]), ]),
), ),
if(selecting)InkWell(child: Container(margin:EdgeInsets.all(10),child: Icon(Icons.edit)),onTap: (){ if (selecting)
selecting=false; InkWell(
selectedActivities=[]; child: Container(margin: EdgeInsets.all(10), child: Icon(Icons.edit)),
setState(() { onTap: () {
selecting = false;
}); selectedActivities = [];
Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewActivity(sTime: activity.trueStartTime,eTime: activity.trueEndTime,metadata: activity.metadata,selectedTask: activity.taskType.name,))).then((value) => UpdateList()); setState(() {});
},) Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) => NewActivity(
sTime: activity.trueStartTime,
eTime: activity.trueEndTime,
metadata: activity.metadata,
selectedTask: activity.taskType.name +
((activity.taskType.relatedProject != null) ? ' [${activity.taskType.relatedProject!.name}]' : ''),
)))
.then((value) => UpdateList());
},
)
]); ]);
} }
@@ -586,11 +625,10 @@ class _ActivitiesState extends State<Activities> {
} }
} }
class ActivityListDateGroup{ class ActivityListDateGroup {
ActivityListDateGroup(this.dateSeperator, this.activities); ActivityListDateGroup(this.dateSeperator, this.activities);
Widget dateSeperator; Widget dateSeperator;
List<Widget> activities; List<Widget> activities;
} }
List<Activity> selectedActivities = []; List<Activity> selectedActivities = [];

View File

@@ -155,7 +155,21 @@ class Journal{
static String colDescription = 'Desc'; static String colDescription = 'Desc';
} }
class Todo{
Todo(this.id, this.category,this.metadata, this.dueDate, {this.notificationTime, this.task});
String id;
String category;
TaskType? task;
String metadata;
DateTime dueDate;
DateTime? notificationTime;
static String colCat = 'category';
static String colMetadata = 'metadata';
static String colDueDate = 'due_date';
static String colNotificationTime = 'notification_time';
}
class Settings{ class Settings{

View File

@@ -310,6 +310,60 @@ class Dialogs{
} }
} }
static showJournalLink(DateTime date) async{
context=navigatorKey.currentContext;
if(context!=null) {
int journalId = -1;
for (int i =0; i < User.journal.length; i++) {
print('${User.journal[i].day } : $date');
if(DateFormat('yyyy-MM-dd').format(User.journal[i].day) == DateFormat('yyyy-MM-dd').format(date)){
journalId = i;
break;
}
}
if(journalId < 0){return;}
String title= '${(User.journal[journalId].title!= null && User.journal[journalId].title!.isNotEmpty) ? User.journal[journalId].title : DateFormat('MMMM-dd').format(date)}';
String description = User.journal[journalId].description ?? '';
if(description.length > 60){
description = description.substring(0,60) + '...(click more for more)';
}
return showDialog(
context: context!,
builder: (BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
backgroundColor: Color(0xFF1C1C1C),
title: Text(title),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(description)
],
),
actions: [
MaterialButton(
onPressed: (){
Navigator.of(context).pop();
},
child: Text('No', style:TextStyle(color: Colors.red)),
),
MaterialButton(
onPressed: (){
Navigator.of(context).pop();
},
child: Text('Yes', style:TextStyle(color: Colors.green)),
)
],
);
}
);
}else{
print('context is null');
}
}
static hide(){ static hide(){
showing=false; showing=false;
Navigator.of(navigatorKey.currentContext!).popUntil((route){ Navigator.of(navigatorKey.currentContext!).popUntil((route){

View File

@@ -80,6 +80,9 @@ class _JournalPageState extends State<JournalPage>{
}); });
},child: Container(margin:EdgeInsets.all(8),child: Icon(Icons.cancel))), },child: Container(margin:EdgeInsets.all(8),child: Icon(Icons.cancel))),
if(!selecting)InkWell(onTap:(){setState(() {
});},child: Container(margin: EdgeInsets.all(8), child: Icon(Icons.refresh),))
], ],
) )
], ],

View File

@@ -37,11 +37,13 @@ bool editing = false;
bool multiLine = true; bool multiLine = true;
String selectedCat = User.categories[0].name; String selectedCat = User.categories[0].name;
String oldName = '[]';
class _NewProjectState extends State<NewProject> { class _NewProjectState extends State<NewProject> {
_NewProjectState({bool? multiline, String? pname, String? selectedCategory, List<ProjectStep>? m_steps, int? m_eta}){ _NewProjectState({bool? multiline, String? pname, String? selectedCategory, List<ProjectStep>? m_steps, int? m_eta}){
multiLine=multiline ?? true; multiLine=multiline ?? true;
nameController.text = pname ?? ''; nameController.text = pname ?? '';
if(pname!=null){oldName=pname;}
if(selectedCategory!=null){selectedCat = selectedCategory;} if(selectedCategory!=null){selectedCat = selectedCategory;}
if(m_steps!=null){steps=m_steps;}else{print('no steps?');} if(m_steps!=null){steps=m_steps;}else{print('no steps?');}
if(multiline!=null && pname != null && selectedCategory != null && m_steps!=null){ if(multiline!=null && pname != null && selectedCategory != null && m_steps!=null){
@@ -500,7 +502,12 @@ class _NewProject2State extends State<NewProject2> {
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom(primary: Colors.green, shape: StadiumBorder()), style: ElevatedButton.styleFrom(primary: Colors.green, shape: StadiumBorder()),
onPressed: () { onPressed: () {
if(editing){
OnClickEdit();
}else{
OnClickAdd(); OnClickAdd();
}
}, },
child: Text((editing) ? 'Apply' : 'Add', style: TextStyle(fontSize: 20))))), child: Text((editing) ? 'Apply' : 'Add', style: TextStyle(fontSize: 20))))),
], ],
@@ -688,6 +695,16 @@ class _NewProject2State extends State<NewProject2> {
return route.isFirst; return route.isFirst;
}); });
} }
void OnClickEdit() async{
if(projectName==null || deadline.isBefore(DateTime.now())){showAlertDialog(context, 'Error', 'Please make sure you have entered correct information'); return;}
User.UserOperations.editProject(oldName,projectName!, selectedCat, steps,etaHours, deadline);
Navigator.of(navigatorKey.currentContext!).popUntil((route){
return route.isFirst;
});
}
} }

View File

@@ -6,7 +6,7 @@ import 'package:tasktracker/NewProject.dart';
import 'Data.dart'; import 'Data.dart';
import 'User.dart' as User; import 'User.dart' as User;
DateFormat dateFormat = DateFormat("yyyy-MM-dd HH:mm:ss"); DateFormat dateTimeFormat = DateFormat("yyyy-MM-dd HH:mm:ss");
DateFormat durationFormat = DateFormat("HH:mm:ss"); DateFormat durationFormat = DateFormat("HH:mm:ss");
class NewTask extends StatefulWidget { class NewTask extends StatefulWidget {

337
lib/NewTodo.dart Normal file
View File

@@ -0,0 +1,337 @@
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:tasktracker/NewTask.dart';
import 'package:tasktracker/NotificationsManager.dart';
import 'Data.dart';
import 'Dialogs.dart';
import 'User.dart' as User;
DateFormat dateFormat = DateFormat("yyyy-MM-dd");
DateFormat dateTimeFormat = DateFormat("yyyy-MM-dd HH:mm");
DateFormat durationFormat = DateFormat("HH:mm:ss");
class NewTodo extends StatefulWidget {
NewTodo({Key? key, this.selectedTask, this.metadata, this.dueDate,this.notificationTime}) : super(key: key);
late String? metadata;
late String? selectedTask;
late DateTime? dueDate;
late DateTime? notificationTime;
@override
_NewActivity createState() => _NewActivity(selectedCat: selectedTask, metadata: metadata);
}
class _NewActivity extends State<NewTodo> {
late String init_selectedTask;
_NewActivity({String? metadata, String? selectedCat, DateTime? DueDate, this.notificationTime}) {
editing =selectedCat != null && DueDate !=null;
dueDate = DueDate ?? DateTime.now().add(Duration(days: 1));
this.metadataController.text = metadata ?? "";
if(this.metadataController.text.contains('[') && this.metadataController.text.contains(']') ){
this.metadataController.text = this.metadataController.text.substring(this.metadataController.text.indexOf(']')+1);
selectedStep = metadata!.substring(1,metadata!.indexOf(']'));
}else{
selectedStep='None';
}
this.init_selectedTask = this.selectedCat = selectedCat ?? User.taskTypes[0].name;
print(" meta:$metadata, task: $selectedCat");
}
TextEditingController metadataController = TextEditingController();
late String selectedCat;
late DateTime dueDate;
DateTime? notificationTime;
bool editing = false;
Map<String, TaskType?> taskTypes = <String, TaskType?>{};
Map<String, TaskType?> getActivities() {
Map<String, TaskType?> _cats = <String, TaskType?>{};
_cats.putIfAbsent("+Add New Task Type", () => null);
if (User.taskTypes.isEmpty) {
} else {
print(User.taskTypes[0].name + " : " + selectedCat);
}
User.taskTypes.forEach((element) {
String name = element.name;
if (_cats.keys.toString().contains(element.name)) {
} else {
String displayName = (name + ((element.relatedProject != null) ? ' [${element.relatedProject!.name}]' : ''));
_cats.putIfAbsent(displayName, () => element);
}
});
return _cats;
}
String? selectedStep = null;
@override
Widget build(BuildContext context) {
taskTypes = getActivities();
bool canSelectStep = false;
List<String> steps = ['None'];
if (taskTypes[selectedCat] != null) {
if (taskTypes[selectedCat]!.relatedProject != null) {
//Got a project. But is it multi step?
if (taskTypes[selectedCat]!.relatedProject!.steps.isNotEmpty) {
canSelectStep = true;
bool matchesSelectedStep = false;
taskTypes[selectedCat]!.relatedProject!.steps.forEach((element) {
if (element.finishedDate == null) {
steps.add(element.stepName);
if (selectedStep == null) {
selectedStep = element.stepName;
matchesSelectedStep = true;
}
if (element.stepName == selectedStep) {
matchesSelectedStep = true;
}
}
});
if (!matchesSelectedStep) {
selectedStep = steps[0];
}
}
}
}
return Scaffold(
appBar: AppBar(title: Text((editing) ? 'Edit To-Do' : 'New To-Do')),
body: Column(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Expanded(
flex: 9,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Padding(
padding: EdgeInsets.fromLTRB(20, 10, 20, 10),
child: Column(
children: [
Column(children: [
Container(padding: EdgeInsets.all(10), child: Text('Task')),
Container(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 1),
decoration: BoxDecoration(
color: Colors.black12, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey, width: 2)),
child: DropdownButton<String>(
dropdownColor: Color(0xFF222222),
iconSize: 30,
elevation: 10,
borderRadius: BorderRadius.circular(10),
value: selectedCat,
isExpanded: true,
items: getActivities().keys.map<DropdownMenuItem<String>>((String value) {
print(value);
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String? _value) {
if (_value == '+Add New Task Type') {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewTask())).then((val) {
setState(() {});
});
} else {
selectedCat = _value ?? 'n/a';
}
setState(() {});
})),
if (canSelectStep) Container(padding: EdgeInsets.all(10), child: Text('Step')),
if (canSelectStep)
Container(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 1),
decoration: BoxDecoration(
color: Colors.black12, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey, width: 2)),
child: DropdownButton<String>(
dropdownColor: Color(0xFF222222),
iconSize: 30,
elevation: 10,
borderRadius: BorderRadius.circular(10),
value: selectedStep,
isExpanded: true,
items: steps.map<DropdownMenuItem<String>>((String value) {
print(value);
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String? _value) {
selectedStep = _value;
setState(() {});
})),
Container(
padding: EdgeInsets.all(10),
child: Column(
children: [
TextField(
controller: metadataController,
decoration: InputDecoration(
hintText: 'Description (required)',
filled: true,
border: OutlineInputBorder(borderRadius: BorderRadius.circular(20))),
),
],
)),
Container(
child: Divider(
)),
ListTile(
leading: FaIcon(FontAwesomeIcons.calendarDay),
title: Text('Due Date'),
subtitle: Text('When do you want to do this?'),
onTap:(){setState(() {
DatePicker.showDatePicker(context, showTitleActions: true, onChanged: (date) {
// print('change $date');
}, onConfirm: (date) {
setState(() {
dueDate=date;
});
}, currentTime: dueDate, locale: LocaleType.en);
});} ,
trailing: InkWell(
child:Text(dateFormat.format(dueDate), style: TextStyle(color: Colors.blue))
),
),
Divider(),
ListTile(
title: Text('Notification'),
leading: FaIcon((notificationTime==null) ?FontAwesomeIcons.bellSlash :FontAwesomeIcons.bell),
trailing: Switch.adaptive(value: notificationTime!=null, onChanged: (val){
if(notificationTime==null){
notificationTime = DateTime.now().add(Duration(days: 1));
}else{
notificationTime = null;
}
setState(() {
});
}),
)
]),
ListTile(
enabled: notificationTime!=null,
leading: FaIcon(FontAwesomeIcons.clock),
title: Text('Notify me at'),
subtitle: Text('When do you want to do this?'),
onTap:(){setState(() {
DatePicker.showDateTimePicker(context, showTitleActions: true, onChanged: (date) {
// print('change $date');
}, onConfirm: (date) {
setState(() {
notificationTime=date;
});
}, currentTime: notificationTime, locale: LocaleType.en);
});} ,
trailing: InkWell(
child:Text(dateTimeFormat.format(notificationTime ?? DateTime.now()), style: TextStyle(color: Colors.blue))
),
),
],
)),
),
),
Expanded(
flex: 1,
child: Container(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 20),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
flex: 5,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
child: ElevatedButton(
style: ElevatedButton.styleFrom(primary: Colors.red, shape: StadiumBorder()),
onPressed: () {
Navigator.pop(context);
},
child: Text('Back', style: TextStyle(fontSize: 20))))),
Expanded(
flex: 6,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
child: ElevatedButton(
style: ElevatedButton.styleFrom(primary: Colors.green, shape: StadiumBorder()),
onPressed: () {
if (editing) {
edit_action();
} else {
add_action();
}
},
child: Text((editing) ? 'Apply' : 'Add Todo', style: TextStyle(fontSize: 20))))),
],
)),
)
]));
}
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 {
if(metadataController.text.isEmpty){
Dialogs.showAlertDialog(context, 'Invalid data', 'Please enter description to add new todo');
return;
}
await User.UserOperations.addTodo(selectedCat, metadataController.text, dueDate, notificationTime);
Navigator.of(context).pop();
}
void edit_action() async {
}
}
String _printDuration(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, "0");
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
}
showAlertDialog(BuildContext context, String title, String message) {
// set up the button
Widget okButton = TextButton(
child: Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text(title),
content: Text(message),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}

View File

@@ -1,82 +0,0 @@
import 'package:flutter/material.dart';
import 'User.dart' as User;
import 'main.dart';
class TodoPage extends StatefulWidget {
const TodoPage({Key? key}) : super(key: key);
@override
State<TodoPage> createState() => _TodoPageState();
}
class _TodoPageState extends State<TodoPage> {
@override
Widget build(BuildContext context) {
return SafeArea(child: Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
// Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewTodo())).then((value) => {User.refreshUserData().then((va) => {})});
},
label: Text("New Todo"),
icon: Icon(Icons.add)),
appBar: AppBar(
title: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(children: [Icon(Icons.check, color: Theme.of(context).primaryColor), SizedBox(width: 10), Text('Todo')]),
Row(
children: [
(User.offline)
? Icon(Icons.signal_cellular_connected_no_internet_4_bar_outlined)
: InkWell(
onTap: () {
setState(() {
//LoadStats();
});
},
child: Icon(Icons.refresh, size: 30),
)
],
)
],
),
//Container(color: Colors.red,child: Text("Offline",style:TextStyle(fontSize: 5))),
],
)),
drawer: navDrawer(context, 7),
body: Column(
children: PrintTodos(),
),
));
}
List<Widget> PrintTodos(){
List<Widget> todos = [];
todos.forEach((element) {
});
todos.add(prioritySeperator('- High Priority (0)'));
todos.add(prioritySeperator('- Low Priority (0)'));
return todos;
}
Widget todoItem(String name){
return Row(children:[Text(name)]);
}
Widget prioritySeperator(String text){
return Padding(
padding: const EdgeInsets.fromLTRB(15,15,15,0),
child: Row(
children: [Text(text,style:TextStyle(fontSize: 18, color: Colors.grey))],
),
);
}
}

278
lib/Todos.dart Normal file
View File

@@ -0,0 +1,278 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
import 'package:tasktracker/NewJournal.dart';
import 'package:tasktracker/NewTodo.dart';
import 'package:tasktracker/main.dart';
import 'User.dart' as User;
import 'Dialogs.dart';
class TodosPage extends StatefulWidget {
const TodosPage({Key? key}) : super(key: key);
@override
State<TodosPage> createState() => _TodosPageState();
}
class _TodosPageState extends State<TodosPage> {
bool selecting = false;
List<int> selectedIndexes = [];
int expandedIndex = -1;
var refreshStream;
@override
void initState() {
// TODO: implement initState
super.initState();
refreshStream = User.refreshStream.stream.listen((event) {
if (!event) {
setState(() {});
}
});
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
refreshStream?.close();
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewTodo())).then((val) {
setState(() {});
});
},
label: Text("New To-Do"),
icon: Icon(Icons.add)),
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
FaIcon(FontAwesomeIcons.calendarCheck),
SizedBox(
width: 15,
),
Text('To-Do')
],
),
Row(
children: [
if (selecting && selectedIndexes.length > 0)
InkWell(
onTap: () async {
selecting = false;
for (int element in selectedIndexes) {
await User.UserOperations.deleteJournal(User.todos[element].id);
}
setState(() {});
},
child: Container(margin: EdgeInsets.all(8), child: Icon(Icons.delete))),
if (selecting)
InkWell(
onTap: () {
selecting = false;
setState(() {});
},
child: Container(margin: EdgeInsets.all(8), child: Icon(Icons.cancel))),
if (!selecting)
InkWell(
onTap: () {
setState(() {});
},
child: Container(
margin: EdgeInsets.all(8),
child: Icon(Icons.refresh),
))
],
)
],
),
),
drawer: navDrawer(context, 9),
body: Container(
padding: EdgeInsets.all(8),
child: ScrollablePositionedList.builder(
itemCount: User.todos.length,
itemBuilder: (context, index) {
int maxCharCount = 100;
bool containsStepData = User.todos[index].metadata.contains('[') && User.todos[index].metadata.contains(']');
return Container(
child: InkWell(
onTap: () {
if (selecting) {
if (selectedIndexes.contains(index)) {
selectedIndexes.remove(index);
} else {
selectedIndexes.add(index);
}
setState(() {});
} else {
if (expandedIndex == index) {
expandedIndex = -1;
//_controller..reverse(from: 0.5);
} else {
expandedIndex = index;
// _controller..forward(from: 0);
}
setState(() {});
}
},
onLongPress: () {
selecting = !selecting;
if (!selectedIndexes.contains(index)) {
selectedIndexes.add(index);
}
setState(() {});
},
child: Row(
children: [
if (selecting)
Checkbox(
value: selectedIndexes.contains(index),
onChanged: (newVal) {
if (selectedIndexes.contains(index)) {
selectedIndexes.remove(index);
} else {
selectedIndexes.add(index);
}
setState(() {});
},
),
Expanded(
child: Column(
children: [
Card(
// color: color,
elevation: 30,
shadowColor: colorFromHex(User.todos[index].task!.cat!.color),
child: InkWell(
onTap: () {
//Open Respective Category
if (selecting) {
//OnItemSelected(activity);
}
setState(() {});
},
onLongPress: () {
print('gonna delete');
selecting = !selecting;
// selectedActivities = [activity];
setState(() {});
},
child: Container(
padding: EdgeInsets.all(15),
child: Column(
children: [
Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.start, children: [
Text(User.todos[index].task!.name, style: TextStyle(fontSize: 17)),
Row(mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.max, children: [
Icon(
Icons.arrow_forward_outlined,
size: 20,
),
SizedBox(
width: MediaQuery.of(context).size.width / 3,
child: Text(
(containsStepData)
? User.todos[index].metadata.substring(User.todos[index].metadata!.indexOf(']') + 1)
: (User.todos[index].metadata ?? ''),
),
),
]),
// Icon(Icons.analytics, color: color, size: 20,),
]),
SizedBox(
height: 5,
),
Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.blue),
child: Text(DateFormat('yyyy-MM-dd').format(User.todos[index].dueDate))),
SizedBox(
width: 20,
),
Row(
children: [
(User.todos[index].task!.relatedProject != null)
? Row(
children: [
if (containsStepData)
Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2),
decoration:
BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.black26),
child: Text(User.todos[index].metadata!
.substring(1, User.todos[index].metadata!.indexOf(']')) ??
'n/a')),
SizedBox(
width: 8,
),
Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2),
decoration:
BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.black26),
child: Text(User.todos[index].task!.relatedProject!.name ?? 'n/a')),
],
)
: Container(),
SizedBox(
width: 10,
),
Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: (User.todos[index].task!.cat!.productive) ? Colors.green : Colors.red),
child: Text(User.todos[index].task!.cat?.name ?? 'n/a')),
],
)
// Icon(Icons.circle,
// color: (productive)
// ? Colors.green
// : Colors.red)
])
],
)))),
Container(
margin: EdgeInsets.fromLTRB(15, 0, 15, 10),
height: 2,
child: Row(
children: [
Expanded(flex: 100, child: Container(color: colorFromHex(User.todos[index].task!.cat!.color))),
Expanded(flex: 0, child: Container())
],
)),
],
),
),
if (selecting)
InkWell(
onTap: () {
// Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewJournal(date: User.todos[index].day, title: User.todos[index].title, text: User.todos[index].description,))).then((val) {
// setState(() {});
// });
selecting = false;
setState(() {});
},
child: Container(margin: EdgeInsets.all(8), child: FaIcon(FontAwesomeIcons.edit)))
],
),
));
}),
),
);
}
}

View File

@@ -29,6 +29,7 @@ List<TaskType> taskTypes = [];
List<Activity> activities = []; List<Activity> activities = [];
List<Project> projects = []; List<Project> projects = [];
List<Journal> journal = []; List<Journal> journal = [];
List<Todo> todos = [];
bool offline = true; bool offline = true;
bool registered = false; bool registered = false;
@@ -80,83 +81,81 @@ Future<void> initUserData() async {
} }
} }
Future<void> BuildBridgeToServer() async{ Future<void> BuildBridgeToServer() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
while(true){ while (true) {
await UserOperations.executeQueries(); await UserOperations.executeQueries();
try { try {
http.Response response = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/bridge.php'), http.Response response =
body: <String, String>{"username": username})); (await http.post(Uri.parse('http://161.97.127.136/task_tracker/bridge.php'), body: <String, String>{"username": username}));
print("bridge retreive (try): ${response.body}"); print("bridge retreive (try): ${response.body}");
List<String> data = response.body.split(","); List<String> data = response.body.split(",");
print('Update :\nactivities_rev=${data[0]} tasks_rev=${data[1]} cats_rev=${data[2]} projects_rev=${data[3]}'); print('Update :\nactivities_rev=${data[0]} tasks_rev=${data[1]} cats_rev=${data[2]} projects_rev=${data[3]}');
if(data[4].contains('<td>')){ if (data[4].contains('<td>')) {
List<String> ongoingData = data[4].split("<td>"); List<String> ongoingData = data[4].split("<td>");
if(!prefs.containsKey('current_activity')) { if (!prefs.containsKey('current_activity')) {
StartActivityTimer(ongoingData[0], ongoingData[1], DateTime.parse(ongoingData[2])); StartActivityTimer(ongoingData[0], ongoingData[1], DateTime.parse(ongoingData[2]));
} }
}else{ } else {
if(prefs.containsKey('current_activity'))CancelOngoingActivity(); if (prefs.containsKey('current_activity')) CancelOngoingActivity();
} }
if(prefs.containsKey('rev')){ if (prefs.containsKey('rev')) {
if(prefs.getString('rev') == response.body){ if (prefs.getString('rev') == response.body) {
print('We are on the same page'); print('We are on the same page');
}else{ } else {
print('Gotta update'); print('Gotta update');
await refreshUserData(); await refreshUserData();
prefs.setString('rev',response.body); prefs.setString('rev', response.body);
} }
}else{ } else {
prefs.setString('rev', response.body); prefs.setString('rev', response.body);
await refreshUserData(); await refreshUserData();
} }
} catch (e) {
}catch(e){
print("Error with bridge : $e"); print("Error with bridge : $e");
} }
await Future.delayed(Duration(seconds: 5)); await Future.delayed(Duration(seconds: 5));
} }
} }
bool m_refreshing = false; bool m_refreshing = false;
Future<void> refreshUserData({bool forceOffline = false}) async { Future<void> refreshUserData({bool forceOffline = false}) async {
print('refreshing user data'); print('refreshing user data');
if(m_refreshing){ if (m_refreshing) {
print('Called while refreshing. Return');return; print('Called while refreshing. Return');
return;
} }
m_refreshing=true; m_refreshing = true;
if(forceOffline) { if (forceOffline) {
refreshStream.add(true); refreshStream.add(true);
categories = await GetCategories(true); categories = await GetCategories(true);
projects= await GetProjects(true); projects = await GetProjects(true);
taskTypes = await GetTaskTypes(true); taskTypes = await GetTaskTypes(true);
activities = await GetActivities(true); activities = await GetActivities(true);
journal = await GetJournals(true); journal = await GetJournals(true);
todos = await GetTodos(true);
refreshStream.add(false); refreshStream.add(false);
}else{ } else {
categories = await GetCategories(false); categories = await GetCategories(false);
projects= await GetProjects(false); projects = await GetProjects(false);
taskTypes = await GetTaskTypes(false); taskTypes = await GetTaskTypes(false);
activities = await GetActivities(false); activities = await GetActivities(false);
journal = await GetJournals(false); journal = await GetJournals(false);
todos= await GetTodos(false);
} }
m_refreshing=false; m_refreshing = false;
if (cacheEnabled) { if (cacheEnabled) {
NotificationManager.RescheduleNotifications(); NotificationManager.RescheduleNotifications();
} }
} }
Future<bool> cacheDbExist() async { Future<bool> cacheDbExist() async {
if (Platform.isAndroid || Platform.isIOS) { if (Platform.isAndroid || Platform.isIOS) {
Directory directory = await getApplicationDocumentsDirectory(); Directory directory = await getApplicationDocumentsDirectory();
@@ -179,7 +178,7 @@ Future<void> updateActList() async {
activities = await GetActivities(false); activities = await GetActivities(false);
} }
Future<void> updateProjectsList() async{ Future<void> updateProjectsList() async {
projects = await GetProjects(false); projects = await GetProjects(false);
} }
@@ -202,7 +201,8 @@ void onCacheDatabaseCreate(Database db, int newVersion) async {
await db.execute(CategoriesTableSQL); await db.execute(CategoriesTableSQL);
print("Initiated Categories Table"); print("Initiated Categories Table");
String TaskTableSQL = 'CREATE TABLE TaskTypes(id TEXT PRIMARY KEY, ${TaskType.colName} TEXT, ${TaskType.colCategory} TEXT, ${TaskType.colRelatedProject} TEXT, ' String TaskTableSQL =
'CREATE TABLE TaskTypes(id TEXT PRIMARY KEY, ${TaskType.colName} TEXT, ${TaskType.colCategory} TEXT, ${TaskType.colRelatedProject} TEXT, '
'FOREIGN KEY (${TaskType.colCategory}) REFERENCES Categories(${Category.colCatId}))'; 'FOREIGN KEY (${TaskType.colCategory}) REFERENCES Categories(${Category.colCatId}))';
// print(TaskTableSQL); // print(TaskTableSQL);
await db.execute(TaskTableSQL); await db.execute(TaskTableSQL);
@@ -219,9 +219,13 @@ void onCacheDatabaseCreate(Database db, int newVersion) async {
String JournalTableSQL = 'CREATE TABLE Journal(id TEXT PRIMARY KEY, ${Journal.colTitle} TEXT, ${Journal.colDescription})'; String JournalTableSQL = 'CREATE TABLE Journal(id TEXT PRIMARY KEY, ${Journal.colTitle} TEXT, ${Journal.colDescription})';
await db.execute(JournalTableSQL); await db.execute(JournalTableSQL);
String TodoTableSQL = 'CREATE TABLE Todos(id TEXT PRIMARY KEY, ${Todo.colCat} TEXT, ${Todo.colMetadata} TEXT, ${Todo.colDueDate} DATE, ${Todo.colNotificationTime} DATETIME)';
await db.execute(TodoTableSQL);
String QueriesTableSQL = 'CREATE TABLE Queries(id INTEGER PRIMARY KEY AUTOINCREMENT, ${Queries.colLink} TEXT,${Queries.colData} TEXT)'; String QueriesTableSQL = 'CREATE TABLE Queries(id INTEGER PRIMARY KEY AUTOINCREMENT, ${Queries.colLink} TEXT,${Queries.colData} TEXT)';
// print(QueriesTableSQL);
await db.execute(QueriesTableSQL); await db.execute(QueriesTableSQL);
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
if (prefs.getBool("registered") ?? false) { if (prefs.getBool("registered") ?? false) {
@@ -232,7 +236,7 @@ void onCacheDatabaseCreate(Database db, int newVersion) async {
} }
Future<void> addInitialDataToCache() async { Future<void> addInitialDataToCache() async {
Dialogs.syncingMessage= "Adding initial data"; Dialogs.syncingMessage = "Adding initial data";
print("adding init data"); print("adding init data");
await Future.delayed(const Duration(seconds: 1)); await Future.delayed(const Duration(seconds: 1));
@@ -240,7 +244,7 @@ Future<void> addInitialDataToCache() async {
for (Category element in InitialData.getCategories(username)) { for (Category element in InitialData.getCategories(username)) {
await UserOperations.addCategory(element.name, element.color, element.productive, bulk: true); await UserOperations.addCategory(element.name, element.color, element.productive, bulk: true);
} }
Dialogs.syncingMessage= "Just a minute"; Dialogs.syncingMessage = "Just a minute";
for (TaskType element in InitialData.getTaskTypes(username)) { for (TaskType element in InitialData.getTaskTypes(username)) {
await UserOperations.addTaskType(element.name, element.category, bulk: true); await UserOperations.addTaskType(element.name, element.category, bulk: true);
// Map<String,Object> data = { // Map<String,Object> data = {
@@ -249,7 +253,7 @@ Future<void> addInitialDataToCache() async {
// }; // };
// await cacheDb.insert('TaskTypes', data); // await cacheDb.insert('TaskTypes', data);
} }
Dialogs.syncingMessage= "Syncing"; Dialogs.syncingMessage = "Syncing";
await UserOperations.executeQueries(); await UserOperations.executeQueries();
// await refreshUserData(); // await refreshUserData();
} }
@@ -390,13 +394,13 @@ Future<List<TaskType>> GetTaskTypes(bool forceOffline) async {
continue; continue;
} }
Project? relatedProject; Project? relatedProject;
if(related_project.isNotEmpty){ if (related_project.isNotEmpty) {
relatedProject = await getProjectFromId(related_project); relatedProject = await getProjectFromId(related_project);
print('got a tasktype with project'); print('got a tasktype with project');
} }
// print("name:{$name}, cat:{$category}, prod:{$id}"); // print("name:{$name}, cat:{$category}, prod:{$id}");
_taskTypes.add(TaskType(id, name, category, cat:cat, relatedProject: relatedProject)); _taskTypes.add(TaskType(id, name, category, cat: cat, relatedProject: relatedProject));
} }
taskTypes = _taskTypes; taskTypes = _taskTypes;
} else { } else {
@@ -412,10 +416,10 @@ Future<List<TaskType>> GetTaskTypes(bool forceOffline) async {
for (var value in data) { for (var value in data) {
Map<String, dynamic> data = jsonDecode(value); Map<String, dynamic> data = jsonDecode(value);
Category? cat = await getCatFromId(data['category_id']); Category? cat = await getCatFromId(data['category_id']);
_taskTypes.add(TaskType(data['task_id'], data['name'], data['category_id'], cat:cat,relatedProject: data['related_project'])); _taskTypes.add(TaskType(data['task_id'], data['name'], data['category_id'], cat: cat, relatedProject: data['related_project']));
//print(cat); //print(cat);
} }
}catch(e){ } catch (e) {
print("Error while tasks NC $e"); print("Error while tasks NC $e");
} }
@@ -437,7 +441,8 @@ Future<void> UpdateTaskTypesFromServer() async {
for (var value in data) { for (var value in data) {
Map<String, dynamic> cat = jsonDecode(value); Map<String, dynamic> cat = jsonDecode(value);
//print(cat); //print(cat);
await cacheDb.rawInsert("INSERT OR REPLACE INTO TaskTypes (${TaskType.colId},${TaskType.colName},${TaskType.colCategory},${TaskType.colRelatedProject}) " await cacheDb
.rawInsert("INSERT OR REPLACE INTO TaskTypes (${TaskType.colId},${TaskType.colName},${TaskType.colCategory},${TaskType.colRelatedProject}) "
"VALUES ('${cat['task_id']}','${cat['name']}','${cat['category_id']}', '${cat['related_project']}') "); "VALUES ('${cat['task_id']}','${cat['name']}','${cat['category_id']}', '${cat['related_project']}') ");
print(await cacheDb.query("TaskTypes")); print(await cacheDb.query("TaskTypes"));
@@ -447,41 +452,37 @@ Future<void> UpdateTaskTypesFromServer() async {
} }
} }
void StartActivityTimer(String taskType, String metadata, DateTime startTime) async {
void StartActivityTimer(String taskType, String metadata, DateTime startTime) async{
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
prefs.setString('current_activity', "$taskType<td>$metadata<td>${UserOperations.dFormat.format(startTime)}"); prefs.setString('current_activity', "$taskType<td>$metadata<td>${UserOperations.dFormat.format(startTime)}");
NotificationManager.RescheduleNotifications(); NotificationManager.RescheduleNotifications();
UserOperations.startOngoing(prefs.getString('current_activity')!); UserOperations.startOngoing(prefs.getString('current_activity')!);
} }
Future<List<String>?> getOngoingData() async{ Future<List<String>?> getOngoingData() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
if(prefs.containsKey('current_activity')){ if (prefs.containsKey('current_activity')) {
List<String> data = []; List<String> data = [];
try{ try {
data = prefs.getString('current_activity')!.split('<td>'); data = prefs.getString('current_activity')!.split('<td>');
return data; return data;
}catch(e){ } catch (e) {}
} } else {}
}else{
}
} }
void StopActivityTimer() async{ void StopActivityTimer() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
try { try {
List<String> data = prefs.getString('current_activity')!.split("<td>"); List<String> data = prefs.getString('current_activity')!.split("<td>");
UserOperations.addActivity(data[0], DateTime.parse(data[2]), DateTime.now(),metadata: data[1]); UserOperations.addActivity(data[0], DateTime.parse(data[2]), DateTime.now(), metadata: data[1]);
}catch(e){} } catch (e) {}
prefs.remove('current_activity'); prefs.remove('current_activity');
UserOperations.stopOngoing(); UserOperations.stopOngoing();
} }
void CancelOngoingActivity() async{ void CancelOngoingActivity() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
prefs.remove('current_activity'); prefs.remove('current_activity');
UserOperations.stopOngoing(); UserOperations.stopOngoing();
@@ -623,7 +624,7 @@ Future<void> UpdateActivitiesFromServer() async {
//print(cat); //print(cat);
await cacheDb.rawInsert( await cacheDb.rawInsert(
"INSERT OR REPLACE INTO Activities (${Activity.colType}, ${Activity.colStartTime}, ${Activity.colEndTime}, ${Activity.colMetadata}) " "INSERT OR REPLACE INTO Activities (${Activity.colType}, ${Activity.colStartTime}, ${Activity.colEndTime}, ${Activity.colMetadata}) "
"VALUES ('${cat['task_id']}', '${cat['sTime']}','${cat['eTime']}', '${cat['metadata']}') "); "VALUES ('${cat['task_id']}', '${cat['sTime']}','${cat['eTime']}', '${cat['metadata'].toString().replaceAll("'", "''")}') ");
} }
} else { } else {
print("No activities for now"); print("No activities for now");
@@ -661,16 +662,20 @@ Future<List<Project>> GetProjects(bool forceOffline) async {
String? category = element[Project.colCat]; String? category = element[Project.colCat];
String? stepsJson = element[Project.colSteps]; String? stepsJson = element[Project.colSteps];
String? deadline = element[Project.colDeadline]; String? deadline = element[Project.colDeadline];
int? eta= element[Project.colEta]; int? eta = element[Project.colEta];
print(name); print(name);
if (name == null || category == null || stepsJson == null || deadline == null || eta==null) { if (name == null || category == null || stepsJson == null || deadline == null || eta == null) {
print("Something is null!\nname:${name == null}, cat:${category == null}, steps:${stepsJson == null}, deadline${deadline == null}"); print("Something is null!\nname:${name == null}, cat:${category == null}, steps:${stepsJson == null}, deadline${deadline == null}");
print("TaskType:{$name}, Start Time:{$category}, endTime:{$stepsJson}, metadata:${deadline}"); print("TaskType:{$name}, Start Time:{$category}, endTime:{$stepsJson}, metadata:${deadline}");
continue; continue;
} }
Category? cat = await getCatFromId(category); Category? cat = await getCatFromId(category);
if(cat==null){print('couldnt find cat');continue;} print('searching for $category');
if (cat == null) {
print('couldnt find cat');
continue;
}
print('steps : $stepsJson'); print('steps : $stepsJson');
List<dynamic> _steps = jsonDecode(stepsJson); List<dynamic> _steps = jsonDecode(stepsJson);
List<ProjectStep> steps = []; List<ProjectStep> steps = [];
@@ -684,7 +689,7 @@ Future<List<Project>> GetProjects(bool forceOffline) async {
eta = (m_eta > 0) ? m_eta : eta; eta = (m_eta > 0) ? m_eta : eta;
// print(steps); // print(steps);
_projects.add(Project(name.replaceAll(username, ""),category,steps,eta,DateTime.parse(deadline),cat: cat)); _projects.add(Project(name.replaceAll(username, ""), category, steps, eta, DateTime.parse(deadline), cat: cat));
} }
projects = _projects; projects = _projects;
} else { } else {
@@ -710,7 +715,6 @@ Future<List<Project>> GetProjects(bool forceOffline) async {
print('null found'); print('null found');
continue; continue;
} }
} }
projects = _projects; projects = _projects;
@@ -795,7 +799,7 @@ Future<List<Journal>> GetJournals(bool forceOffline) async {
} }
DateTime day = DateTime.parse(id.replaceAll(username, '')); DateTime day = DateTime.parse(id.replaceAll(username, ''));
// print("name:{$catName}, color:{$catColor}, prod:{$catProductive}"); // print("name:{$catName}, color:{$catColor}, prod:{$catProductive}");
_journals.add(Journal(id,day,title: title,description: text)); _journals.add(Journal(id, day, title: title, description: text));
} }
journal = _journals; journal = _journals;
} else { } else {
@@ -810,14 +814,15 @@ Future<List<Journal>> GetJournals(bool forceOffline) async {
for (var value in data) { for (var value in data) {
Map<String, dynamic> cat = jsonDecode(value); Map<String, dynamic> cat = jsonDecode(value);
//print(catData); //print(catData);
_categories.add(Journal(cat['id'],DateTime.parse(cat['id'].toString().replaceAll(username, '')), title:cat['title'], description:cat['text'])); _categories
.add(Journal(cat['id'], DateTime.parse(cat['id'].toString().replaceAll(username, '')), title: cat['title'], description: cat['text']));
} }
journal = _categories; journal = _categories;
} catch (e) { } catch (e) {
print("Error while cats NC: $e"); print("Error while cats NC: $e");
} }
} }
journal.sort((a,b)=> b.day.compareTo(a.day)); journal.sort((a, b) => b.day.compareTo(a.day));
return journal; return journal;
} }
@@ -833,8 +838,7 @@ Future<void> UpdateJournalsFromServer() async {
for (var value in data) { for (var value in data) {
Map<String, dynamic> cat = jsonDecode(value); Map<String, dynamic> cat = jsonDecode(value);
//print(catData); //print(catData);
await cacheDb await cacheDb.rawInsert("INSERT OR REPLACE INTO Journal (id, ${Journal.colTitle},${Journal.colDescription}) "
.rawInsert("INSERT OR REPLACE INTO Journal (id, ${Journal.colTitle},${Journal.colDescription}) "
"VALUES ('${cat['id']}','${cat['title'].toString().replaceAll("'", "''")}','${cat['description'].toString().replaceAll("'", "''")}') "); "VALUES ('${cat['id']}','${cat['title'].toString().replaceAll("'", "''")}','${cat['description'].toString().replaceAll("'", "''")}') ");
} }
} catch (e) { } catch (e) {
@@ -842,6 +846,100 @@ Future<void> UpdateJournalsFromServer() async {
} }
} }
Future<List<Todo>> GetTodos(bool forceOffline) async {
if (cacheEnabled) {
List<Todo> _todos = [];
if (offline || forceOffline) {
//Retreive from cacheDB
} else {
//Check if server got updated, If not go for cache
//Validate device_id to check updates
bool catsUpdated = false;
// try {
// http.Response update_response = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/check_update.php'), body: <String, String>{"username": username, "device_id": android_id}));
// final data = update_response.body.split(',');
// catsUpdated = data[0] == '1';
// } catch (e) {
// print(e);
// }
//Update CacheDB
if (!catsUpdated) {
await UpdateTodosFromServer();
}
}
List<Map> cats = await cacheDb.query('Todos');
print(cats.length);
for (Map element in cats) {
String? id = element['id'].toString();
String? task_id = element[Todo.colCat];
String? metadata = element[Todo.colMetadata];
String? due_date = element[Todo.colDueDate];
String? notification_time = element[Todo.colNotificationTime];
if (id == null || task_id == null || metadata == null || due_date == null) {
print("Something is null!");
print("id:{$id}, task:{$task_id}, metadata:${metadata}, due_date: ${due_date}");
continue;
}
TaskType? taskType = await getTaskFromId(task_id);
if(taskType == null){print('got null taask for this todo!');print("id:{$id}, task:{$task_id}, metadata:${metadata}, due_date: ${due_date}");}
DateTime dueDate = DateTime.parse(due_date);
DateTime? notificationTime = (notification_time == null) ? null : ((notification_time.isEmpty || notification_time =='null') ? null :DateTime.parse(notification_time));
// print("name:{$catName}, color:{$catColor}, prod:{$catProductive}");
_todos.add(Todo(id,task_id,metadata,dueDate, notificationTime: notificationTime, task:taskType));
}
todos = _todos;
} else {
print("NC: Updating todos as $username");
try {
http.Response response = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/get_todos.php'),
body: <String, String>{"username": username, "device_id": await Settings.UUID()}));
print(response.body);
List<String> data = response.body.split("<td>");
List<Journal> _categories = [];
for (var value in data) {
Map<String, dynamic> cat = jsonDecode(value);
//print(catData);
_categories
.add(Journal(cat['id'], DateTime.parse(cat['id'].toString().replaceAll(username, '')), title: cat['title'], description: cat['text']));
}
journal = _categories;
} catch (e) {
print("Error while cats NC: $e");
}
}
// journal.sort((a, b) => b.day.compareTo(a.day));
return todos;
}
Future<void> UpdateTodosFromServer() async {
print("Updating Todos as $username");
try {
http.Response response = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/get_todos.php'),
body: <String, String>{"username": username, "device_id": await Settings.UUID()}));
print(response.body);
List<String> data = response.body.split("<td>");
await cacheDb.delete("Todos");
for (var value in data) {
Map<String, dynamic> cat = jsonDecode(value);
//print(catData);
await cacheDb.rawInsert("INSERT OR REPLACE INTO Todos (id, ${Todo.colCat},${Todo.colMetadata},${Todo.colDueDate},${Todo.colNotificationTime}) "
"VALUES ('${cat['id'].toString().replaceAll("'", "''")}', '${cat['task_id']}', '${cat['metadata'].toString().replaceAll("'", "''")}', '${cat['due_date']}', '${cat['notification_time']}') ");
}
} catch (e) {
print("Error while cats $e");
}
}
Future<TaskType?> getTaskFromId(String taskId) async { Future<TaskType?> getTaskFromId(String taskId) async {
// await GetTaskTypes(false); // await GetTaskTypes(false);
TaskType? cat = null; TaskType? cat = null;
@@ -874,7 +972,7 @@ Future<Project?> getProjectFromId(String projectId) async {
// await GetTaskTypes(false); // await GetTaskTypes(false);
Project? project = null; Project? project = null;
for (var element in projects) { for (var element in projects) {
if (element.getName() ==projectId.replaceAll(username, "")) { if (element.getName() == projectId.replaceAll(username, "")) {
project = element; project = element;
} }
} }
@@ -885,6 +983,19 @@ Future<Project?> getProjectFromId(String projectId) async {
return project; return project;
} }
bool journalExists(DateTime date){
int journalId = -1;
for (int i =0; i < journal.length; i++) {
// print('${journal[i].day } : $date');
if(DateFormat('yyyy-MM-dd').format(journal[i].day) == DateFormat('yyyy-MM-dd').format(date)){
journalId = i;
break;
}
}
return (journalId > 0);
}
//Helpers //Helpers
class Helpers { class Helpers {
Future<String?> _getId() async { Future<String?> _getId() async {
@@ -957,7 +1068,7 @@ class UserOperations {
'device_id': await Settings.UUID(), 'device_id': await Settings.UUID(),
'name': name, 'name': name,
'category': username + category, 'category': username + category,
'related_project' :(relatedProject==null) ? '' : (username + relatedProject) 'related_project': (relatedProject == null) ? '' : (username + relatedProject)
}; };
if (cacheEnabled) { if (cacheEnabled) {
@@ -969,8 +1080,14 @@ class UserOperations {
await cacheDb.insert('Queries', query); await cacheDb.insert('Queries', query);
//update Cache //update Cache
Map<String, Object> data = {TaskType.colId: username + name, Category.colName: name, Category.colCatId: username + category,}; Map<String, Object> data = {
if(relatedProject!=null || relatedProject =='None'){data.putIfAbsent(TaskType.colRelatedProject, () => relatedProject.toString());} TaskType.colId: username + name,
Category.colName: name,
Category.colCatId: username + category,
};
if (relatedProject != null || relatedProject == 'None') {
data.putIfAbsent(TaskType.colRelatedProject, () => relatedProject.toString());
}
await cacheDb.insert('TaskTypes', data); await cacheDb.insert('TaskTypes', data);
await refreshUserData(forceOffline: true); await refreshUserData(forceOffline: true);
} else { } else {
@@ -996,7 +1113,7 @@ class UserOperations {
'username': username, 'username': username,
'name': name, 'name': name,
'category': username + category, 'category': username + category,
'related_project' :(relatedProject==null) ? '' : (username + relatedProject) 'related_project': (relatedProject == null) ? '' : (username + relatedProject)
}; };
if (cacheEnabled) { if (cacheEnabled) {
@@ -1008,7 +1125,8 @@ class UserOperations {
await cacheDb.insert('Queries', query); await cacheDb.insert('Queries', query);
//update Cache //update Cache
await cacheDb.rawUpdate("UPDATE TaskTypes SET ${TaskType.colId}='${username+name}', ${TaskType.colName}='$name', ${TaskType.colCategory}='${username+category}', ${TaskType.colRelatedProject}='${(relatedProject == 'None') ? '' : relatedProject}' WHERE id='${username+oldName}'"); await cacheDb.rawUpdate(
"UPDATE TaskTypes SET ${TaskType.colId}='${username + name}', ${TaskType.colName}='$name', ${TaskType.colCategory}='${username + category}', ${TaskType.colRelatedProject}='${(relatedProject == 'None') ? '' : relatedProject}' WHERE id='${username + oldName}'");
await refreshUserData(forceOffline: true); await refreshUserData(forceOffline: true);
} else { } else {
try { try {
@@ -1193,7 +1311,7 @@ class UserOperations {
await executeQueries(); await executeQueries();
} }
static Future<void> addProject(String name, String category, List<ProjectStep> steps,int eta, DateTime deadline) async { static Future<void> addProject(String name, String category, List<ProjectStep> steps, int eta, DateTime deadline) async {
Map<String, String> queryBody = <String, String>{ Map<String, String> queryBody = <String, String>{
'name': username + name, 'name': username + name,
'username': username, 'username': username,
@@ -1213,7 +1331,13 @@ class UserOperations {
await cacheDb.insert('Queries', query); await cacheDb.insert('Queries', query);
//update Cache //update Cache
Map<String, Object> data = {Project.colName: username+name, Project.colCat: category, Project.colSteps: jsonEncode(steps),Project.colEta: eta, Project.colDeadline: deadline.toString()}; Map<String, Object> data = {
Project.colName: username + name,
Project.colCat: category,
Project.colSteps: jsonEncode(steps),
Project.colEta: eta,
Project.colDeadline: deadline.toString()
};
await cacheDb.insert('Projects', data); await cacheDb.insert('Projects', data);
await refreshUserData(forceOffline: true); await refreshUserData(forceOffline: true);
} else { } else {
@@ -1231,16 +1355,60 @@ class UserOperations {
await executeQueries(); await executeQueries();
} }
static Future<void> CompleteProjectStep(Project project, ProjectStep step, DateTime finishedDate) async { static Future<void> editProject(String oldName, String name, String category, List<ProjectStep> steps, int eta, DateTime deadline) async {
Map<String, String> queryBody = <String, String>{
'oldName': username + oldName,
'name': username + name,
'username': username,
'category_id': username + category,
'steps': jsonEncode(steps),
'eta': eta.toString(),
'deadline': DateFormat("yyyy-MM-dd").format(deadline)
};
if (cacheEnabled) {
//Add Query
Map<String, Object> query = {Queries.colLink: 'edit_project', Queries.colData: jsonEncode(queryBody)};
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
await cacheDb.insert('Queries', query);
//update Cache
Map<String, Object> data = {
Project.colName: username + name,
Project.colCat: category,
Project.colSteps: jsonEncode(steps),
Project.colEta: eta,
Project.colDeadline: deadline.toString()
};
await cacheDb.rawUpdate(
"UPDATE Projects SET ${Project.colName}='${username + name}', ${Project.colCat}='${username+category}', ${Project.colSteps}='${jsonEncode(steps)}', ${Project.colEta}='${eta}', ${Project.colDeadline}='${deadline.toString()}' WHERE ${Project.colName}='${username+oldName}'");
await cacheDb.rawUpdate("UPDATE TaskTypes SET ${TaskType.colRelatedProject}='${username+name}' WHERE ${TaskType.colRelatedProject}='${username+oldName}'");
await refreshUserData(forceOffline: true);
} else {
try {
http.Response queryResponse = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/edit_project.php'), body: queryBody));
print("Query executed : Results{${queryResponse.body}");
if (queryResponse.body.toLowerCase().contains("success")) {
//Success
}
} catch (e) {
print('NC: Error adding prjct $e}');
}
}
await executeQueries();
}
static Future<void> CompleteProjectStep(Project project, ProjectStep step, DateTime finishedDate) async {
project.steps.forEach((element) { project.steps.forEach((element) {
if(element.stepName == step.stepName){ if (element.stepName == step.stepName) {
element.finishedDate = finishedDate; element.finishedDate = finishedDate;
} }
}); });
Map<String, String> queryBody = <String, String>{ Map<String, String> queryBody = <String, String>{
'name': username+project.name, 'name': username + project.name,
'username': username, 'username': username,
'steps': jsonEncode(project.steps), 'steps': jsonEncode(project.steps),
}; };
@@ -1273,15 +1441,14 @@ class UserOperations {
} }
static Future<void> UndoProjectStep(Project project, ProjectStep step) async { static Future<void> UndoProjectStep(Project project, ProjectStep step) async {
project.steps.forEach((element) { project.steps.forEach((element) {
if(element.stepName == step.stepName){ if (element.stepName == step.stepName) {
element.finishedDate = null; element.finishedDate = null;
} }
}); });
Map<String, String> queryBody = <String, String>{ Map<String, String> queryBody = <String, String>{
'name': username+project.name, 'name': username + project.name,
'username': username, 'username': username,
'steps': jsonEncode(project.steps), 'steps': jsonEncode(project.steps),
}; };
@@ -1314,23 +1481,19 @@ class UserOperations {
} }
static Future<void> addJournal(DateTime day, String title, String text) async { static Future<void> addJournal(DateTime day, String title, String text) async {
bool exist = false;
bool exist =false;
for (var element in journal) { for (var element in journal) {
if(element.day== day){ if (element.day == day) {
//Wat! //Wat!
exist=true; exist = true;
break; break;
} }
} }
if(exist){return;} if (exist) {
return;
}
String id = username + DateFormat('yyyy-MM-dd').format(day); String id = username + DateFormat('yyyy-MM-dd').format(day);
Map<String, String> queryBody = <String, String>{ Map<String, String> queryBody = <String, String>{'username': username, 'id': id, 'title': title, 'description': text};
'username': username,
'id': id,
'title': title,
'description': text
};
if (cacheEnabled) { if (cacheEnabled) {
//Add Query //Add Query
Map<String, Object> query = {Queries.colLink: 'add_journal', Queries.colData: jsonEncode(queryBody)}; Map<String, Object> query = {Queries.colLink: 'add_journal', Queries.colData: jsonEncode(queryBody)};
@@ -1340,11 +1503,7 @@ class UserOperations {
await cacheDb.insert('Queries', query); await cacheDb.insert('Queries', query);
//update Cache //update Cache
Map<String, Object> data = { Map<String, Object> data = {'id': id, Journal.colTitle: title, Journal.colDescription: text};
'id':id,
Journal.colTitle: title,
Journal.colDescription:text
};
await cacheDb.insert('Journal', data); await cacheDb.insert('Journal', data);
await refreshUserData(forceOffline: true); await refreshUserData(forceOffline: true);
} else { } else {
@@ -1361,18 +1520,12 @@ class UserOperations {
} }
//Add to server and refresh Cache //Add to server and refresh Cache
await executeQueries(); await executeQueries();
} }
static Future<void> editJournal(DateTime oldDay, DateTime day, String title, String text) async { static Future<void> editJournal(DateTime oldDay, DateTime day, String title, String text) async {
String oldId = username + DateFormat('yyyy-MM-dd').format(oldDay); String oldId = username + DateFormat('yyyy-MM-dd').format(oldDay);
String id = username + DateFormat('yyyy-MM-dd').format(day); String id = username + DateFormat('yyyy-MM-dd').format(day);
Map<String, String> queryBody = <String, String>{ Map<String, String> queryBody = <String, String>{'username': username, 'old_id': oldId, 'id': id, 'title': title, 'description': text};
'username': username,
'old_id':oldId,
'id': id,
'title': title,
'description': text
};
if (cacheEnabled) { if (cacheEnabled) {
//Add Query //Add Query
Map<String, Object> query = {Queries.colLink: 'edit_journal', Queries.colData: jsonEncode(queryBody)}; Map<String, Object> query = {Queries.colLink: 'edit_journal', Queries.colData: jsonEncode(queryBody)};
@@ -1380,13 +1533,10 @@ class UserOperations {
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
await cacheDb.insert('Queries', query); await cacheDb.insert('Queries', query);
await cacheDb.rawUpdate("UPDATE Journal SET id='$id', ${Journal.colTitle}='${title.toString().replaceAll("'", "''")}', ${Journal.colDescription}='${text.toString().replaceAll("'", "''")}' WHERE id='$oldId'"); await cacheDb.rawUpdate(
"UPDATE Journal SET id='$id', ${Journal.colTitle}='${title.toString().replaceAll("'", "''")}', ${Journal.colDescription}='${text.toString().replaceAll("'", "''")}' WHERE id='$oldId'");
//update Cache //update Cache
Map<String, Object> data = { Map<String, Object> data = {'id': id, Journal.colTitle: title, Journal.colDescription: text};
'id':id,
Journal.colTitle: title,
Journal.colDescription:text
};
// await cacheDb.insert('Journal', data); // await cacheDb.insert('Journal', data);
await refreshUserData(forceOffline: true); await refreshUserData(forceOffline: true);
} else { } else {
@@ -1403,9 +1553,54 @@ class UserOperations {
} }
//Add to server and refresh Cache //Add to server and refresh Cache
await executeQueries(); await executeQueries();
} }
static Future<void> addTodo(String taskType, String metadata, DateTime dueDate, DateTime? notificationTime) async {
String taskId = username + taskType;
if(taskId.contains('[') && taskId.contains(']')){
//has a project related
taskId = taskId.substring(0, taskId.indexOf('[') - 1);
}
String id = username + taskId + metadata;
Map<String, String> queryBody = <String, String>{
'username': username,
'task': taskId,
'metadata': metadata,
'due_date': DateFormat('yyyy-MM-dd').format(dueDate),
if(notificationTime!=null)'notification_time':DateFormat('yyyy-MM-dd HH:mm').format(notificationTime)
};
if (cacheEnabled) {
//Add Query
Map<String, Object> query = {Queries.colLink: 'add_todo', Queries.colData: jsonEncode(queryBody)};
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
await cacheDb.insert('Queries', query);
//update Cache
Map<String, Object> data = {'id': id, Todo.colCat: username+taskType, Todo.colMetadata: metadata, Todo.colDueDate: DateFormat('yyyy-MM-dd').format(dueDate), if(notificationTime!=null)Todo.colNotificationTime:DateFormat('yyyy-MM-dd HH:mm').format(notificationTime)};
await cacheDb.insert('Todos', data);
await refreshUserData(forceOffline: true);
} else {
try {
http.Response queryResponse = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/add_todo.php'), body: queryBody));
print("Query executed : Results{${queryResponse.body}");
if (queryResponse.body.toLowerCase().contains("success")) {
//Success
}
} catch (e) {
print('NC: Error adding journal entry $e}');
}
//executeQueries();
}
//Add to server and refresh Cache
await executeQueries();
}
static Future<void> deleteTask(String name, {bulk = false}) async { static Future<void> deleteTask(String name, {bulk = false}) async {
Map<String, String> queryBody = <String, String>{ Map<String, String> queryBody = <String, String>{
'id': username + name, 'id': username + name,
@@ -1523,7 +1718,7 @@ class UserOperations {
static Future<void> deleteProject(String project, {bulk = false}) async { static Future<void> deleteProject(String project, {bulk = false}) async {
Map<String, String> queryBody = <String, String>{ Map<String, String> queryBody = <String, String>{
'username': username, 'username': username,
'name': username+project, 'name': username + project,
}; };
//Add Query //Add Query
Map<String, Object> query = {Queries.colLink: 'delete_project', Queries.colData: jsonEncode(queryBody)}; Map<String, Object> query = {Queries.colLink: 'delete_project', Queries.colData: jsonEncode(queryBody)};
@@ -1534,8 +1729,7 @@ class UserOperations {
await cacheDb.insert('Queries', query); await cacheDb.insert('Queries', query);
//update Cache //update Cache
String deleteQuery = String deleteQuery = "DELETE FROM Projects WHERE ${Project.colName}='${username + project}'";
"DELETE FROM Projects WHERE ${Project.colName}='${username+project}'";
print("delteQuery : $deleteQuery"); print("delteQuery : $deleteQuery");
await cacheDb.rawDelete(deleteQuery); await cacheDb.rawDelete(deleteQuery);
@@ -1571,8 +1765,7 @@ class UserOperations {
await cacheDb.insert('Queries', query); await cacheDb.insert('Queries', query);
//update Cache //update Cache
String deleteQuery = String deleteQuery = "DELETE FROM Journal WHERE id='$id'";
"DELETE FROM Journal WHERE id='$id'";
print("delteQuery : $deleteQuery"); print("delteQuery : $deleteQuery");
await cacheDb.rawDelete(deleteQuery); await cacheDb.rawDelete(deleteQuery);
@@ -1617,7 +1810,7 @@ class UserOperations {
try { try {
http.Response queryResponse = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/$file.php'), body: body)); http.Response queryResponse = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/$file.php'), body: body));
print("Query executed : Results{${queryResponse.body}"); print("Query executed : Results{${queryResponse.body}");
if (queryResponse.body.toLowerCase().contains("success")) { if (queryResponse.body.toLowerCase().contains("+")) {
await cacheDb.rawDelete('DELETE FROM Queries WHERE id=$id'); await cacheDb.rawDelete('DELETE FROM Queries WHERE id=$id');
} }
offline = false; offline = false;

View File

@@ -12,7 +12,7 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:tasktracker/Categories.dart'; import 'package:tasktracker/Categories.dart';
import 'package:tasktracker/Journal.dart'; import 'package:tasktracker/Journal.dart';
import 'package:tasktracker/Projects.dart'; import 'package:tasktracker/Projects.dart';
import 'package:tasktracker/Todo.dart'; import 'package:tasktracker/Todos.dart';
import 'package:tasktracker/Welcome.dart'; import 'package:tasktracker/Welcome.dart';
import 'package:tasktracker/splash.dart'; import 'package:tasktracker/splash.dart';
import 'package:tasktracker/theme_provider.dart'; import 'package:tasktracker/theme_provider.dart';
@@ -113,7 +113,8 @@ class MyApp extends StatelessWidget {
'/Activities': (context) => const Activities(), '/Activities': (context) => const Activities(),
'/Settings': (context) => const SettingsPage(), '/Settings': (context) => const SettingsPage(),
'/Projects':(context)=> const Projects(), '/Projects':(context)=> const Projects(),
'/Journal': (context)=> const JournalPage() '/Journal': (context)=> const JournalPage(),
'/Todos':(context)=> const TodosPage()
}); });
}); });
} }
@@ -205,7 +206,7 @@ class _MyHomePageState extends State<MyHomePage> {
// } // }
hourglassTime = ((DateTime.now().hour * 60) + DateTime.now().minute) / 1440; hourglassTime = ((DateTime.now().hour * 60) + DateTime.now().minute) / 1440;
// hourglassTime = 1; // hourglassTime = 1;
print('hourglass time : $hourglassTime'); // print('hourglass time : $hourglassTime');
hourglassColors =[]; hourglassColors =[];
hourglassStops = []; hourglassStops = [];
hourglassTotalTime=0; hourglassTotalTime=0;
@@ -214,11 +215,11 @@ class _MyHomePageState extends State<MyHomePage> {
hourglassTotalTime+=element.time; hourglassTotalTime+=element.time;
// } // }
}); });
print('hourglass cat data'); // print('hourglass cat data');
double stopsTotal = 0; double stopsTotal = 0;
for(int i =0 ; i < hourglassCatData.length; i++) { for(int i =0 ; i < hourglassCatData.length; i++) {
CatMapData element = hourglassCatData[i]; CatMapData element = hourglassCatData[i];
print('${element.name} : ${element.time} / $hourglassTotalTime = ${element.time / hourglassTotalTime}'); // print('${element.name} : ${element.time} / $hourglassTotalTime = ${element.time / hourglassTotalTime}');
double thisStop = ( element.time/hourglassTotalTime); double thisStop = ( element.time/hourglassTotalTime);
hourglassColors.add(element.color); hourglassColors.add(element.color);
hourglassStops.add(stopsTotal+thisStop); hourglassStops.add(stopsTotal+thisStop);
@@ -228,14 +229,14 @@ class _MyHomePageState extends State<MyHomePage> {
hourglassStops.add(stopsTotal+thisStop + 0.001); hourglassStops.add(stopsTotal+thisStop + 0.001);
} }
} }
print('total Stops ${stopsTotal}'); // print('total Stops ${stopsTotal}');
print('maxT: $hourglassTotalTime'); // print('maxT: $hourglassTotalTime');
if(hourglassColors.isEmpty){ if(hourglassColors.isEmpty){
hourglassColors.add(Colors.black); hourglassColors.add(Colors.black);
hourglassStops.add(1); hourglassStops.add(1);
} }
print('hourglass \n$hourglassColors \n$hourglassStops'); // print('hourglass \n$hourglassColors \n$hourglassStops');
setState(() { setState(() {
}); });
@@ -292,6 +293,7 @@ class _MyHomePageState extends State<MyHomePage> {
} }
} }
bool loadingStats = false; bool loadingStats = false;
DateFormat dFormat = DateFormat("yyyy-MM-dd");
void LoadStats() async { void LoadStats() async {
// return; // return;
// await User.refreshUserData(); // await User.refreshUserData();
@@ -304,7 +306,7 @@ class _MyHomePageState extends State<MyHomePage> {
} }
await Refresh(); await Refresh();
DateFormat dFormat = DateFormat("MM/dd");
Map<Category, int> catTimeMap = <Category, int>{}; Map<Category, int> catTimeMap = <Category, int>{};
Map<Category, int> catBriefMap = <Category, int>{}; Map<Category, int> catBriefMap = <Category, int>{};
@@ -354,13 +356,16 @@ class _MyHomePageState extends State<MyHomePage> {
taskTypesDuration.putIfAbsent(element.taskType, () => thisMinutes); taskTypesDuration.putIfAbsent(element.taskType, () => thisMinutes);
} }
} }
if ((element.startTime.isAfter(prodRange!.start) && element.startTime.isBefore(prodRange!.end)) ||
(dFormat.format(element.startTime) == dFormat.format(prodRange!.start) || dFormat.format(element.startTime) == dFormat.format(prodRange!.end))) {
if (element.taskType.cat?.productive ?? false) { if (element.taskType.cat?.productive ?? false) {
if (lastProductive == null) { if (lastProductive == null) {
lastProductive = element.trueEndTime; lastProductive = element.trueEndTime;
} }}
if ((element.startTime.isAfter(prodRange!.start) && element.startTime.isBefore(prodRange!.end)) ||
(dFormat.format(element.startTime) == dFormat.format(prodRange!.start) || dFormat.format(element.startTime) == dFormat.format(prodRange!.end))) {
if (element.taskType.cat?.productive ?? false) {
// if (lastProductive == null) {
// lastProductive = element.trueEndTime;
// }
if (productivtyActs.containsKey(thisDate)) { if (productivtyActs.containsKey(thisDate)) {
productivtyActs[thisDate] = (productivtyActs[thisDate]! + thisMinutes); productivtyActs[thisDate] = (productivtyActs[thisDate]! + thisMinutes);
} else { } else {
@@ -728,15 +733,19 @@ class _MyHomePageState extends State<MyHomePage> {
series: <LineSeries<ProductivityMapData, String>>[ series: <LineSeries<ProductivityMapData, String>>[
LineSeries<ProductivityMapData, String>( LineSeries<ProductivityMapData, String>(
// Bind data source // Bind data source
markerSettings: MarkerSettings(isVisible: true, shape: DataMarkerType.circle),
dataSource: productivityData.reversed.toList(), dataSource: productivityData.reversed.toList(),
xValueMapper: (ProductivityMapData sales, _) => sales.day, xValueMapper: (ProductivityMapData sales, _) => DateFormat('MM-dd').format(dFormat.parse(sales.day)),
yValueMapper: (ProductivityMapData sales, _) => sales.productivity, yValueMapper: (ProductivityMapData sales, _) => sales.productivity,
dataLabelMapper: (ProductivityMapData sales, _) => sales.productivity.toStringAsFixed(1) + "%", dataLabelMapper: (ProductivityMapData sales, _) => sales.productivity.toStringAsFixed(1) + "%",
dataLabelSettings: DataLabelSettings(overflowMode: OverflowMode.hide, showZeroValue: false, isVisible: true), dataLabelSettings: DataLabelSettings(overflowMode: OverflowMode.hide, showZeroValue: false, isVisible: true),
onPointTap: (ChartPointDetails point){ onPointTap: (ChartPointDetails point){
showAlertDialog(context, productivityData[point.pointIndex!].day, "I'll show you detailed info about this day in future, When my master creates the feature"); Dialogs.showJournalLink(dFormat.parse(productivityData[productivityData.length-point.pointIndex!-1].day));
//showAlertDialog(context, productivityData[point.pointIndex!].day, "I'll show you detailed info about this day in future, When my master creates the feature");
}, },
color: Colors.green) pointColorMapper: (ProductivityMapData sales, _)=> (User.journalExists(dFormat.parse(sales.day)) ? Colors.lightGreenAccent : Colors.green)
)
//color: User.journalExists(dFormat.parse(productivityData[(productivityData.length-point.pointIndex!-1) as int].day)) ?Colors.green : Colors.red,
]), ]),
), ),
SizedBox(height: 20,), SizedBox(height: 20,),
@@ -778,7 +787,6 @@ class _MyHomePageState extends State<MyHomePage> {
child: SfCircularChart(legend: Legend(isVisible: true,position: LegendPosition.bottom,overflowMode: LegendItemOverflowMode.wrap), series: <CircularSeries>[ child: SfCircularChart(legend: Legend(isVisible: true,position: LegendPosition.bottom,overflowMode: LegendItemOverflowMode.wrap), series: <CircularSeries>[
// Render pie chart // Render pie chart
PieSeries<CatMapData, String>( PieSeries<CatMapData, String>(
dataSource: dailyData, dataSource: dailyData,
pointColorMapper: (CatMapData data, _) => data.color, pointColorMapper: (CatMapData data, _) => data.color,
xValueMapper: (CatMapData data, _) => data.name, xValueMapper: (CatMapData data, _) => data.name,
@@ -1013,6 +1021,17 @@ Drawer navDrawer(BuildContext context, int pageIndex) {
Navigator.of(context).pushReplacementNamed('/Projects'); Navigator.of(context).pushReplacementNamed('/Projects');
}, },
), ),
ListTile(
selected: (pageIndex == 9),
title: Text('To-Do'),
leading: FaIcon(FontAwesomeIcons.calendarCheck, color: Theme.of(context).primaryColor),
onTap: () {
if (pageIndex == 9) {
return;
}
Navigator.of(context).pushReplacementNamed('/Todos');
},
),
ListTile( ListTile(
selected: (pageIndex == 8), selected: (pageIndex == 8),
title: Text('Journal'), title: Text('Journal'),

View File

@@ -7,7 +7,8 @@ import 'package:tasktracker/NotificationsManager.dart';
import 'package:tasktracker/main.dart'; import 'package:tasktracker/main.dart';
import 'Data.dart'; import 'Data.dart';
import 'User.dart' as User; import 'User.dart' as User;
DateFormat dateFormat = DateFormat("yyyy-MM-dd HH:mm:ss");
DateFormat dateTimeFormat = DateFormat("yyyy-MM-dd HH:mm:ss");
DateFormat durationFormat = DateFormat("HH:mm:ss"); DateFormat durationFormat = DateFormat("HH:mm:ss");
class NewActivity extends StatefulWidget { class NewActivity extends StatefulWidget {
@@ -17,24 +18,27 @@ class NewActivity extends StatefulWidget {
late String? metadata; late String? metadata;
late String? selectedTask; late String? selectedTask;
@override @override
_NewActivity createState() => _NewActivity(eTime: eTime, sTime: sTime,selectedCat: selectedTask, metadata: metadata); _NewActivity createState() => _NewActivity(eTime: eTime, sTime: sTime, selectedCat: selectedTask, metadata: metadata);
} }
class _NewActivity extends State<NewActivity> { class _NewActivity extends State<NewActivity> {
late DateTime init_sTime; late DateTime init_sTime;
late DateTime init_eTime; late DateTime init_eTime;
late String init_selectedTask; late String init_selectedTask;
_NewActivity({DateTime? eTime, DateTime? sTime, String? metadata, String? selectedCat}){ _NewActivity({DateTime? eTime, DateTime? sTime, String? metadata, String? selectedCat}) {
editing = sTime != null && eTime!=null && selectedCat!=null; editing = sTime != null && eTime != null && selectedCat != null;
this.init_sTime=this.startTime = sTime ?? DateTime.now(); this.init_sTime = this.startTime = sTime ?? DateTime.now();
this.init_eTime=this.endTime = eTime ??DateTime.now().add(Duration(minutes: 30)); this.init_eTime = this.endTime = eTime ?? DateTime.now().add(Duration(minutes: 30));
this.metadataController.text = metadata ?? ""; this.metadataController.text = metadata ?? "";
this.init_selectedTask=this.selectedCat = selectedCat ?? User.taskTypes[0].name; if(this.metadataController.text.contains('[') && this.metadataController.text.contains(']') ){
this.metadataController.text = this.metadataController.text.substring(this.metadataController.text.indexOf(']')+1);
selectedStep = metadata!.substring(1,metadata!.indexOf(']'));
}else{
selectedStep='None';
}
this.init_selectedTask = this.selectedCat = selectedCat ?? User.taskTypes[0].name;
print("etime:$eTime, sTime:$sTime, meta:$metadata, task: $selectedCat"); print("etime:$eTime, sTime:$sTime, meta:$metadata, task: $selectedCat");
} }
late DateTime startTime; late DateTime startTime;
@@ -42,56 +46,74 @@ class _NewActivity extends State<NewActivity> {
TextEditingController metadataController = TextEditingController(); TextEditingController metadataController = TextEditingController();
late String selectedCat; late String selectedCat;
bool editing = false;
bool editing=false; Map<String, TaskType?> taskTypes = <String, TaskType?>{};
Map<String, TaskType?> getActivities() {
List<String> getActivities(){ Map<String, TaskType?> _cats = <String, TaskType?>{};
List<String> _cats = []; _cats.putIfAbsent("+Add New Task Type", () => null);
_cats.add("+Add New Task Type"); if (User.taskTypes.isEmpty) {
if(User.taskTypes.isEmpty){ } else {
}else {
print(User.taskTypes[0].name + " : " + selectedCat); print(User.taskTypes[0].name + " : " + selectedCat);
} }
User.taskTypes.forEach((element) { User.taskTypes.forEach((element) {
String name = element.name; String name = element.name;
if(_cats.contains(element.name)){ if (_cats.keys.toString().contains(element.name)) {
} else {
}else{ String displayName = (name + ((element.relatedProject != null) ? ' [${element.relatedProject!.name}]' : ''));
_cats.add(name + ((element.relatedProject !=null) ? ' [${element.relatedProject!.name}]' :'')); _cats.putIfAbsent(displayName, () => element);
} }
}); });
return _cats; return _cats;
} }
String? selectedStep = null;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
taskTypes = getActivities();
bool canSelectStep = false;
List<String> steps = ['None'];
if (taskTypes[selectedCat] != null) {
if (taskTypes[selectedCat]!.relatedProject != null) {
//Got a project. But is it multi step?
if (taskTypes[selectedCat]!.relatedProject!.steps.isNotEmpty) {
canSelectStep = true;
bool matchesSelectedStep = false;
taskTypes[selectedCat]!.relatedProject!.steps.forEach((element) {
if (element.finishedDate == null) {
steps.add(element.stepName);
if (selectedStep == null) {
selectedStep = element.stepName;
matchesSelectedStep = true;
}
if (element.stepName == selectedStep) {
matchesSelectedStep = true;
}
}
});
if (!matchesSelectedStep) {
selectedStep = steps[0];
}
}
}
}
return Scaffold( return Scaffold(
appBar: AppBar(title: Text((editing) ? 'Edit Activity':'New Activity')), appBar: AppBar(title: Text((editing) ? 'Edit Activity' : 'New Activity')),
body:Column( body: Column(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded( Expanded(
flex: 9, flex: 9,
child: SingleChildScrollView( child: SingleChildScrollView(
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
child: Padding( child: Padding(
padding: EdgeInsets.fromLTRB(20, 50, 20, 50), padding: EdgeInsets.fromLTRB(20, 10, 20, 10),
child: Column( child: Column(
children: [ children: [
Column(children: [ Column(children: [
Container(padding: EdgeInsets.all(10), child: Text('Task')),
Container( Container(
padding: EdgeInsets.all(10), padding: EdgeInsets.symmetric(horizontal: 12, vertical: 1),
child: Text('Task')),
Container(
padding: EdgeInsets.symmetric(
horizontal: 12, vertical: 1),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.black12, color: Colors.black12, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey, width: 2)),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Colors.grey, width: 2)),
child: DropdownButton<String>( child: DropdownButton<String>(
dropdownColor: Color(0xFF222222), dropdownColor: Color(0xFF222222),
iconSize: 30, iconSize: 30,
@@ -99,8 +121,7 @@ class _NewActivity extends State<NewActivity> {
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
value: selectedCat, value: selectedCat,
isExpanded: true, isExpanded: true,
items: getActivities().map<DropdownMenuItem<String>>( items: getActivities().keys.map<DropdownMenuItem<String>>((String value) {
(String value) {
print(value); print(value);
return DropdownMenuItem<String>( return DropdownMenuItem<String>(
value: value, value: value,
@@ -108,91 +129,90 @@ class _NewActivity extends State<NewActivity> {
); );
}).toList(), }).toList(),
onChanged: (String? _value) { onChanged: (String? _value) {
if(_value == '+Add New Task Type'){ if (_value == '+Add New Task Type') {
Navigator.of(context).push(MaterialPageRoute(builder: (context)=> NewTask())).then((val){setState(() { Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewTask())).then((val) {
setState(() {});
});});
}else{
selectedCat = _value ?? 'n/a';
}
setState(() {
}); });
} else {
selectedCat = _value ?? 'n/a';
}
setState(() {});
})),
if (canSelectStep) Container(padding: EdgeInsets.all(10), child: Text('Step')),
if (canSelectStep)
Container(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 1),
decoration: BoxDecoration(
color: Colors.black12, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey, width: 2)),
child: DropdownButton<String>(
dropdownColor: Color(0xFF222222),
iconSize: 30,
elevation: 10,
borderRadius: BorderRadius.circular(10),
value: selectedStep,
isExpanded: true,
items: steps.map<DropdownMenuItem<String>>((String value) {
print(value);
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String? _value) {
selectedStep = _value;
setState(() {});
})), })),
Container( Container(
padding: EdgeInsets.all(10), padding: EdgeInsets.all(10),
child:Column( child: Column(
children: [ children: [
TextField( TextField(
controller: metadataController, controller: metadataController,
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'Description (optional)', hintText: 'Description (optional)',
filled: true, filled: true,
border: OutlineInputBorder( border: OutlineInputBorder(borderRadius: BorderRadius.circular(20))),
borderRadius: BorderRadius.circular(20)
)
),
), ),
], ],
) )),
),
Container( Container(
child: Divider( child: Divider(
height: 30, height: 30,
)), )),
Container( Container(padding: EdgeInsets.all(10), child: Text('Start Time')),
padding: EdgeInsets.all(10),
child: Text('Start Time')),
Row( Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
QuickTimeButton('Last', Function: (){ QuickTimeButton('Last', Function: () {
if(User.activities.length > 0) { if (User.activities.length > 0) {
startTime= User.activities[0].endTime; startTime = User.activities[0].endTime;
} }
}) }),
,
Container( Container(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(horizontal: 12, vertical: 1),
horizontal: 12, vertical: 1), decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey, width: 2)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Colors.grey, width: 2)),
child: MaterialButton( child: MaterialButton(
onPressed: () { onPressed: () {
setState(() { setState(() {
DatePicker.showDateTimePicker( DatePicker.showDateTimePicker(context, maxTime: endTime, showTitleActions: true, onChanged: (date) {
context,
maxTime: endTime,
showTitleActions: true,
onChanged: (date) {
// print('change $date'); // print('change $date');
}, onConfirm: (date) { }, onConfirm: (date) {
setState(() { setState(() {
if(endTime.compareTo(date) < 0){ if (endTime.compareTo(date) < 0) {
const snackBar = SnackBar( const snackBar = SnackBar(
content: Text('You cannot start something after you ended it!'), content: Text('You cannot start something after you ended it!'),
); );
ScaffoldMessenger.of(context).showSnackBar(snackBar); ScaffoldMessenger.of(context).showSnackBar(snackBar);
}else { } else {
startTime = date; startTime = date;
} }
}); });
}, }, currentTime: startTime, locale: LocaleType.en);
currentTime: startTime,
locale: LocaleType.en);
}); });
}, },
child: Text( child: Text(dateTimeFormat.format(startTime), style: TextStyle(color: Colors.blue)))),
dateFormat.format(startTime), QuickTimeButton('Now', Function: () {
style: TextStyle(
color: Colors.blue)))),
QuickTimeButton('Now', Function: (){
startTime = DateTime.now(); startTime = DateTime.now();
}) })
], ],
@@ -200,67 +220,54 @@ class _NewActivity extends State<NewActivity> {
SizedBox( SizedBox(
height: 10, height: 10,
), ),
Container( Container(padding: EdgeInsets.all(10), child: Text('Ended Time')),
padding: EdgeInsets.all(10),
child: Text('Ended Time')),
Row( Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
Container(width: 60,),
Container( Container(
padding: EdgeInsets.symmetric( width: 60,
horizontal: 12, vertical: 1), ),
decoration: BoxDecoration( Container(
borderRadius: BorderRadius.circular(12), padding: EdgeInsets.symmetric(horizontal: 12, vertical: 1),
border: Border.all( decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey, width: 2)),
color: Colors.grey, width: 2)),
child: MaterialButton( child: MaterialButton(
onPressed: () { onPressed: () {
setState(() { setState(() {
DatePicker.showDateTimePicker( DatePicker.showDateTimePicker(context, showTitleActions: true, minTime: startTime, onChanged: (date) {
context,
showTitleActions: true,
minTime: startTime,
onChanged: (date) {
// print('change $date'); // print('change $date');
}, onConfirm: (date) { }, onConfirm: (date) {
setState(() { setState(() {
if(startTime.compareTo(date) > 0){ if (startTime.compareTo(date) > 0) {
const snackBar = SnackBar( const snackBar = SnackBar(
content: Text('You cannot end something before you start it!'), content: Text('You cannot end something before you start it!'),
); );
ScaffoldMessenger.of(context).showSnackBar(snackBar); ScaffoldMessenger.of(context).showSnackBar(snackBar);
}else { } else {
endTime = date; endTime = date;
} }
}); });
}, }, currentTime: endTime, locale: LocaleType.en);
currentTime: endTime,
locale: LocaleType.en);
}); });
}, },
child: Text(dateFormat.format(endTime), child: Text(dateTimeFormat.format(endTime), style: TextStyle(color: Colors.blue)))),
style: TextStyle( QuickTimeButton('Now', Function: () {
color: Colors.blue)))),
QuickTimeButton('Now', Function: (){
endTime = DateTime.now(); endTime = DateTime.now();
}) })
], ],
), ),
SizedBox(height: 15,), SizedBox(
(!editing)?Container( height: 15,
),
(!editing)
? Container(
child: Card( child: Card(
shadowColor: Colors.blue, shadowColor: Colors.blue,
elevation: 20, elevation: 20,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
// color: Color(0xAA51AAFF), // color: Color(0xAA51AAFF),
color: Colors.deepPurpleAccent, color: Colors.deepPurpleAccent,
child: Column( child: Column(mainAxisSize: MainAxisSize.max, children: [
mainAxisSize: MainAxisSize.max,
children:[
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Row( child: Row(
@@ -269,48 +276,51 @@ class _NewActivity extends State<NewActivity> {
children: [ children: [
Icon(Icons.lightbulb, color: Colors.yellowAccent), Icon(Icons.lightbulb, color: Colors.yellowAccent),
Text('Not finished yet?', style: TextStyle(fontSize: 18)), Text('Not finished yet?', style: TextStyle(fontSize: 18)),
Container(width: 15,), Container(
width: 15,
),
], ],
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Text('Click following button to start tracking an unfinished Activity. Activity will be added when you finish it.', textAlign: TextAlign.center,), child: Text(
'Click following button to start tracking an unfinished Activity. Activity will be added when you finish it.',
textAlign: TextAlign.center,
),
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: MaterialButton( child: MaterialButton(
color: Colors.green, color: Colors.green,
onPressed: (){ onPressed: () {
User.StartActivityTimer(selectedCat, metadataController.text, startTime); User.StartActivityTimer(selectedCat, metadataController.text, startTime);
//Go home and show card //Go home and show card
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20,vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Icon(Icons.access_time), Icon(Icons.access_time),
SizedBox(width: 10,), SizedBox(
width: 10,
),
Text('Start Timer'), Text('Start Timer'),
], ],
), ),
), ),
), ),
) )
] ])),
) )
), : Container(),
) : Container(),
SizedBox( SizedBox(
height: 30, height: 30,
), ),
Text('Duration : ' + Text('Duration : ' + _printDuration(endTime.difference(startTime)),
_printDuration( style: TextStyle(
endTime.difference(startTime)),
style:TextStyle(
fontSize: 20, fontSize: 20,
)), )),
Divider( Divider(
@@ -318,22 +328,17 @@ class _NewActivity extends State<NewActivity> {
), ),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [],
],
) )
]), ]),
], ],
)), )),
), ),
), ),
Expanded( Expanded(
flex: 1, flex: 1,
child: Container( child: Container(
padding: padding: EdgeInsets.symmetric(vertical: 10, horizontal: 20),
EdgeInsets.symmetric(vertical: 10, horizontal: 20),
child: Row( child: Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
@@ -343,105 +348,96 @@ class _NewActivity extends State<NewActivity> {
child: Container( child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0), padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom(primary: Colors.red, shape: StadiumBorder()),
style:ElevatedButton.styleFrom(
primary: Colors.red,
shape: StadiumBorder()
),
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
}, },
child: Text('Back', child: Text('Back', style: TextStyle(fontSize: 20))))),
style: TextStyle(fontSize: 20))))),
Expanded( Expanded(
flex: 6, flex: 6,
child: Container( child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0), padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
child: ElevatedButton( child: ElevatedButton(
style:ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(primary: Colors.green, shape: StadiumBorder()),
primary: Colors.green,
shape: StadiumBorder()
),
onPressed: () { onPressed: () {
if(editing){ if (editing) {
edit_action(); edit_action();
}else { } else {
add_action(); add_action();
} }
}, },
child: Text((editing) ? 'Apply':'Add Activity', child: Text((editing) ? 'Apply' : 'Add Activity', style: TextStyle(fontSize: 20))))),
style: TextStyle(fontSize: 20))))),
], ],
)), )),
) )
])); ]));
} }
Widget QuickTimeButton(text, {Function}){ Widget QuickTimeButton(text, {Function}) {
return InkWell( return InkWell(
child: Container( child: Container(
padding:EdgeInsets.symmetric(horizontal: 15), padding: EdgeInsets.symmetric(horizontal: 15),
height: 30, height: 30,
decoration:BoxDecoration( decoration: BoxDecoration(color: Colors.blueAccent, borderRadius: BorderRadius.circular(50)),
color: Colors.blueAccent, child: Align(
borderRadius: BorderRadius.circular(50) child: Text(text),
), alignment: Alignment.center,
child:Align(child: Text(text),alignment: Alignment.center,) )),
), onTap: () {
onTap: (){
Function(); Function();
setState(() { setState(() {});
},
}); );
},);
} }
void add_action() async{ void add_action() async {
if(startTime.isAfter(endTime)){ if (startTime.isAfter(endTime)) {
showAlertDialog(context, 'Really?', 'Start time and end time doesnt make any sense'); showAlertDialog(context, 'Really?', 'Start time and end time doesnt make any sense');
} }
String selectedTasks = selectedCat; String selectedTasks = selectedCat;
if(selectedTasks.contains('[') && selectedTasks.contains(']')){ if (selectedTasks.contains('[') && selectedTasks.contains(']')) {
selectedTasks = selectedTasks.substring(0, selectedTasks.indexOf('[')-1); selectedTasks = selectedTasks.substring(0, selectedTasks.indexOf('[') - 1);
print('Project task : $selectedTasks'); print('Project task : $selectedTasks');
} }
print('adding Task Type : $selectedTasks at $startTime - $endTime'); print('adding Task Type : $selectedTasks at $startTime - $endTime');
bool failed=false; bool failed = false;
await User.UserOperations.addActivity(selectedTasks,startTime, endTime,metadata:metadataController.text, onOverlap: (overlapCount){ await User.UserOperations.addActivity(selectedTasks, startTime, endTime, metadata:((selectedStep!=null && selectedStep != 'None') ? '[$selectedStep]' : '')+ 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',
failed=true; 'Cannot add activity between ${dateTimeFormat.format(startTime)} - ${dateTimeFormat.format(endTime)}, $overlapCount activities are already added within this time range');
failed = true;
}); });
if(!failed) { if (!failed) {
print("popping : ${navigatorKey.currentWidget?.toStringShort() ?? "n/a"}"); print("popping : ${navigatorKey.currentWidget?.toStringShort() ?? "n/a"}");
Navigator.of(navigatorKey.currentContext!).popUntil((route){ Navigator.of(navigatorKey.currentContext!).popUntil((route) {
return route.isFirst; return route.isFirst;
}); });
}else{ } else {
print("Failed adding new activity"); print("Failed adding new activity");
} }
} }
void edit_action() async{ void edit_action() async {
String selectedTasks = selectedCat; String selectedTasks = selectedCat;
if(selectedTasks.contains('[') && selectedTasks.contains(']')){ if (selectedTasks.contains('[') && selectedTasks.contains(']')) {
selectedTasks = selectedTasks.substring(0, selectedTasks.indexOf('[')-1); selectedTasks = selectedTasks.substring(0, selectedTasks.indexOf('[') - 1);
print('Project task : $selectedTasks'); print('Project task : $selectedTasks');
} }
print('adding Task Type : $selectedTasks at $startTime - $endTime'); print('adding Task Type : $selectedTasks at $startTime - $endTime');
bool failed=false; bool failed = false;
await User.UserOperations.editActivity(init_sTime,init_eTime,selectedTasks,startTime, endTime,metadata:metadataController.text, onOverlap: (overlapCount){ await User.UserOperations.editActivity(init_sTime, init_eTime, selectedTasks, startTime, endTime,metadata: ((selectedStep!=null && selectedStep != 'None') ? '[$selectedStep]' : '')+ metadataController.text,
showAlertDialog(context, 'Error editing activity', 'Cannot add activity between ${dateFormat.format(startTime)} - ${dateFormat.format(endTime)}, $overlapCount activities are already added within this time range'); onOverlap: (overlapCount) {
failed=true; showAlertDialog(context, 'Error editing activity',
'Cannot add activity between ${dateTimeFormat.format(startTime)} - ${dateTimeFormat.format(endTime)}, $overlapCount activities are already added within this time range');
failed = true;
}); });
if(!failed) { if (!failed) {
print("popping : ${navigatorKey.currentWidget?.toStringShort() ?? "n/a"}"); print("popping : ${navigatorKey.currentWidget?.toStringShort() ?? "n/a"}");
Navigator.of(navigatorKey.currentContext!).popUntil((route){ Navigator.of(navigatorKey.currentContext!).popUntil((route) {
return route.isFirst; return route.isFirst;
}); });
}else{ } else {
print("Failed editing new activity"); print("Failed editing new activity");
} }
} }
@@ -455,11 +451,12 @@ String _printDuration(Duration duration) {
} }
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