diff --git a/lib/tools/todo/models/todo_model.dart b/lib/tools/todo/models/todo_model.dart index 1d14b6f..f5fe11b 100644 --- a/lib/tools/todo/models/todo_model.dart +++ b/lib/tools/todo/models/todo_model.dart @@ -1,42 +1,51 @@ class Todo { final int? id; - final String title; + final String name; final DateTime date; - final DateTime remindDate; + final String notificationTime; + final String notificationFrequency; final String color; - final String pictureAttachment; - final String note; + final String description; + final bool complete; + final DateTime dateAdded; Todo({ this.id, - required this.title, + required this.name, required this.date, - required this.remindDate, + required this.notificationTime, + required this.notificationFrequency, required this.color, - required this.pictureAttachment, - required this.note, - }); + required this.description, + required this.complete, + DateTime? dateAdded, + }) : dateAdded = dateAdded ?? DateTime.now(); factory Todo.fromJson(Map json) { return Todo( - id: json['id'], - title: json['title'], + id: json['id'] as int?, + name: json['name'] as String, date: DateTime.parse(json['date']), - remindDate: DateTime.parse(json['remindDate']), - color: json['color'], - pictureAttachment: json['pictureAttachment'], - note: json['note'], + notificationTime: json['notificationTime'], + notificationFrequency: json['notificationFrequency'] as String, + color: json['color'] as String, + description: json['description'] as String, + complete: json['complete'] as bool, + dateAdded: DateTime.parse(json['dateAdded']), ); } Map toJson() { return { - 'title': title, + 'id': id, + 'name': name, 'date': date.toIso8601String(), - 'remindDate': remindDate.toIso8601String(), + 'notificationTime': notificationTime, + 'notificationFrequency': notificationFrequency, 'color': color, - 'pictureAttachment': pictureAttachment, - 'note': note, + 'description': description, + 'complete': complete, + 'dateAdded': dateAdded.toIso8601String(), }; } } diff --git a/lib/tools/todo/models/todo_model_helper.dart b/lib/tools/todo/models/todo_model_helper.dart index 3db6bb8..c9dfda0 100644 --- a/lib/tools/todo/models/todo_model_helper.dart +++ b/lib/tools/todo/models/todo_model_helper.dart @@ -1,55 +1,71 @@ import 'package:academia/storage/storage.dart'; +import 'todo_model.dart'; import 'package:sqflite/sqflite.dart'; class TodoModelHelper { static final TodoModelHelper _instance = TodoModelHelper._internal(); factory TodoModelHelper() { - DatabaseHelper().registerModel('todos', ''' - id INTEGER PRIMARY KEY AUTOINCREMENT, - title TEXT NOT NULL, - date TEXT NOT NULL, - remindDate TEXT NOT NULL, - color TEXT NOT NULL, - pictureAttachment TEXT, - note TEXT, - '''); - return _instance; } TodoModelHelper._internal(); - Future create(Map data) async { + // Register the table schema + void registerModel(Database db) { + db.execute(''' + CREATE TABLE IF NOT EXISTS todos ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + date TEXT NOT NULL, + notificationTime TEXT NOT NULL, + notificationFrequency TEXT NOT NULL, + color TEXT NOT NULL, + description TEXT, + complete INTEGER NOT NULL, + dateAdded TEXT NOT NULL + ) + '''); + } + + // Insert a new Todo + Future insert(Todo todo) async { final db = await DatabaseHelper().database; - final id = await db.insert( + return await db.insert( 'todos', - data, + todo.toJson(), conflictAlgorithm: ConflictAlgorithm.replace, ); - - return id; } - Future>> queryAll() async { + // Get all Todos + Future> getAllTodos() async { final db = await DatabaseHelper().database; - final todos = await db.query('todos'); - return todos; - } + final List> maps = await db.query('todos'); - Future delete(int id) async { - final db = await DatabaseHelper().database; - return await db.delete('todos', where: 'id =?', whereArgs: [id]); + return List.generate(maps.length, (i) { + return Todo.fromJson(maps[i]); + }); } - Future update(Map data) async { + // Update a Todo + Future update(Todo todo) async { final db = await DatabaseHelper().database; - return await db - .update('todos', data, where: 'id =?', whereArgs: [data['id']]); + return await db.update( + 'todos', + todo.toJson(), + where: 'id =?', + whereArgs: [todo.id], + ); } - Future truncate() async { + // Delete a Todo + Future delete(int id) async { final db = await DatabaseHelper().database; - await db.execute('DELETE FROM todos'); + return await db.delete( + 'todos', + where: 'id =?', + whereArgs: [id], + ); } } diff --git a/lib/tools/todo/todo_view_page.dart b/lib/tools/todo/todo_view_page.dart index 8c92032..ed0080c 100644 --- a/lib/tools/todo/todo_view_page.dart +++ b/lib/tools/todo/todo_view_page.dart @@ -1,6 +1,6 @@ import 'package:academia/exports/barrel.dart'; -import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:flex_color_picker/flex_color_picker.dart'; class TodoViewPage extends StatefulWidget { const TodoViewPage({super.key}); @@ -9,35 +9,30 @@ class TodoViewPage extends StatefulWidget { State createState() => _TodoViewPageState(); } -enum _NotificationFrequency { - everyDay, - dayBefore, -} - class _TodoViewPageState extends State { TextEditingController titleController = TextEditingController(); TextEditingController noteController = TextEditingController(); DateTime? _selectedDate; TimeOfDay? _notificationTime; + Color? _selectedColor; + bool _completed = false; + bool _selectedFrequency = false; final formKey = GlobalKey(); final DateFormat formatter = DateFormat('EEEE, MMM yyyy'); final DateFormat timeformatter = DateFormat('HH:mm'); void _presentDatePicker() { - // showDatePicker is a pre-made funtion of Flutter showDatePicker( context: context, initialDate: DateTime.now(), firstDate: DateTime(2020), lastDate: DateTime(2030)) .then((pickedDate) { - // Check if no date is selected if (pickedDate == null) { return; } setState(() { - // using state so that the UI will be rerendered when date is picked _selectedDate = pickedDate; }); }); @@ -59,22 +54,70 @@ class _TodoViewPageState extends State { void _presentFrequencyPicker() { showDialog( - context: context, - builder: (context) { - return SimpleDialog( - title: Text("Reminder Frequency"), - children: [ - SimpleDialogOption( - child: Text("Every Day"), - onPressed: () {}, + context: context, + builder: (context) => AlertDialog( + title: const Text("Notification Frequency"), + actions: [ + FilledButton( + onPressed: () { + Navigator.of(context).pop(); + _presentTimePicker(); + }, + child: const Text("Confirm")), + FilledButton.tonal( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text("Cancel")), + ], + content: StatefulBuilder( + builder: (context, StateSetter setState) { + return SizedBox( + height: 150, + child: Column( + children: [ + RadioListTile( + title: const Text("Every Day"), + value: true, + groupValue: + _selectedFrequency, // Assuming you have a variable to hold the selected frequency + onChanged: (bool? value) { + setState(() { + _selectedFrequency = value!; + }); + }, + ), + RadioListTile( + title: const Text("Day Before"), + value: false, + groupValue: + _selectedFrequency, // Assuming you have a variable to hold the selected frequency + onChanged: (bool? value) { + setState(() { + _selectedFrequency = value!; + }); + }, + ), + ], ), - SimpleDialogOption( - child: Text("Every Day"), - onPressed: () {}, - ) - ], - ); + ); + }, + ), + ), + ); + } + + void _presentColorPicker() { + ColorPicker( + color: Colors.teal, + onColorChanged: (Color color) { + setState(() { + _selectedColor = color; }); + }, + ).showPickerDialog( + context, + ); } @override @@ -83,7 +126,8 @@ class _TodoViewPageState extends State { appBar: AppBar( title: const Text("Agenda Item"), actions: [ - IconButton(onPressed: () {}, icon: const Icon(Ionicons.save_outline)) + IconButton(onPressed: () {}, icon: const Icon(Ionicons.trash)), + IconButton(onPressed: () {}, icon: const Icon(Ionicons.save_outline)), ], leading: IconButton( onPressed: () { @@ -99,34 +143,23 @@ class _TodoViewPageState extends State { key: formKey, child: Column( children: [ - Row( - children: [ - Radio( - value: false, - groupValue: "Completed", - onChanged: (value) {}, - ), - Expanded( - child: TextFormField( - controller: titleController, - autovalidateMode: AutovalidateMode.onUserInteraction, - validator: (value) { - if ((value?.length ?? 0) < 3) { - return "Please specify a valid title"; - } - return null; - }, - decoration: InputDecoration( - hintText: "Add task name", - hintStyle: Theme.of(context) - .textTheme - .titleLarge - ?.copyWith(color: Colors.grey), - border: InputBorder.none, - ), - ), - ) - ], + TextFormField( + controller: titleController, + autovalidateMode: AutovalidateMode.onUserInteraction, + validator: (value) { + if ((value?.length ?? 0) < 3) { + return "Please specify a valid title"; + } + return null; + }, + decoration: InputDecoration( + hintText: "Add agenda title", + hintStyle: Theme.of(context) + .textTheme + .titleLarge + ?.copyWith(color: Colors.grey), + border: InputBorder.none, + ), ), const Divider(), Padding( @@ -157,7 +190,9 @@ class _TodoViewPageState extends State { style: Theme.of(context).textTheme.titleMedium, ), subtitle: Text( - "Day before", + _selectedFrequency + ? "Every day to that day" + : "Just day before", style: Theme.of(context) .textTheme .titleSmall @@ -169,10 +204,14 @@ class _TodoViewPageState extends State { Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: ListTile( - onTap: () {}, - leading: const CircleAvatar( + onTap: () { + _presentColorPicker(); + }, + leading: CircleAvatar( radius: 10, - backgroundColor: Colors.red, + backgroundColor: _selectedColor == null + ? Colors.teal + : _selectedColor!, ), title: Text( "Pick a color", @@ -183,6 +222,13 @@ class _TodoViewPageState extends State { Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: TextFormField( + autovalidateMode: AutovalidateMode.onUserInteraction, + validator: (value) { + if ((value?.length ?? 0) < 5) { + return "Please describe this task to make it memorable"; + } + return null; + }, controller: noteController, maxLines: 7, decoration: InputDecoration( @@ -195,6 +241,16 @@ class _TodoViewPageState extends State { ), ), ), + const Divider(height: 20), + FilledButton.icon( + onPressed: () {}, + icon: Icon( + _completed ? Ionicons.pricetag_outline : Ionicons.checkmark, + ), + label: Text( + _completed ? "Umark as complete" : "Mark as complete", + ), + ) ], ), ), diff --git a/pubspec.yaml b/pubspec.yaml index a74ae9d..6d538db 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -70,6 +70,7 @@ dependencies: awesome_notifications: ^0.8.2 sqflite: ^2.3.3 path: ^1.9.0 + flex_color_picker: ^3.4.1