348 lines
15 KiB
Dart
348 lines
15 KiB
Dart
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 'DebugHelper.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, this.old_id}) : super(key: key);
|
|
late String? old_id;
|
|
late String? metadata;
|
|
late String? selectedTask;
|
|
late DateTime? dueDate;
|
|
late DateTime? notificationTime;
|
|
@override
|
|
_NewActivity createState() => _NewActivity(selectedCat: selectedTask, metadata: metadata, DueDate: dueDate, notificationTime: notificationTime,oldId: old_id);
|
|
}
|
|
|
|
class _NewActivity extends State<NewTodo> {
|
|
late String init_selectedTask;
|
|
_NewActivity({String? metadata, String? selectedCat, DateTime? DueDate, this.notificationTime, this.oldId}) {
|
|
Debug.Log('selected cat : $selectedCat');
|
|
editing =selectedCat != null && DueDate !=null && metadata !=null && oldId!=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;
|
|
Debug.Log(" meta:$metadata, task: $selectedCat, notification_time : ${notificationTime}");
|
|
}
|
|
|
|
TextEditingController metadataController = TextEditingController();
|
|
late String selectedCat;
|
|
late DateTime dueDate;
|
|
DateTime? notificationTime;
|
|
|
|
bool editing = false;
|
|
String? oldId;
|
|
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 = TaskType.getDisplayName(element);
|
|
_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,((selectedStep!=null && selectedStep != 'None') ? '[$selectedStep]' : '')+ metadataController.text, dueDate, notificationTime);
|
|
Navigator.of(context).pop();
|
|
}
|
|
|
|
void edit_action() async {
|
|
if(metadataController.text.isEmpty){
|
|
Dialogs.showAlertDialog(context, 'Invalid data', 'Please enter description to add new todo');
|
|
return;
|
|
}
|
|
|
|
await User.UserOperations.editTodo(oldId!,selectedCat,((selectedStep!=null && selectedStep != 'None') ? '[$selectedStep]' : '')+ metadataController.text, dueDate, notificationTime);
|
|
Navigator.of(context).pop();
|
|
}
|
|
}
|
|
|
|
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;
|
|
},
|
|
);
|
|
}
|