Skip to content

Commit

Permalink
feat: storing todos
Browse files Browse the repository at this point in the history
- Now one can store a todo item in the db
- Displaying todos in the agenda homescreen tab
  • Loading branch information
IamMuuo committed May 6, 2024
1 parent 5843e53 commit a28c98f
Show file tree
Hide file tree
Showing 12 changed files with 191 additions and 106 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Miscellaneous
*.db
*.class
*.lock
*.log
Expand Down
Binary file removed academia.db
Binary file not shown.
Binary file removed db-file.db
Binary file not shown.
Empty file removed db.file.db
Empty file.
1 change: 1 addition & 0 deletions lib/exports/barrel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ export 'package:academia/tools/time_line/time_line_page.dart';
export 'package:academia/tools/stories/notifications_story_page.dart';
export 'package:academia/controllers/controllers.dart';
export 'package:awesome_notifications/awesome_notifications.dart';
export 'package:academia/tools/todo/todo.dart';
12 changes: 1 addition & 11 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,6 @@ void main() async {
StorageService().registerAdapters<Task>(TaskAdapter());
StorageService().registerAdapters<Exam>(ExamAdapter());

// Initialize the various controllers
// once you append the controller onto the list don't inject it again
// since it will be placed in the context
// ControllerService().injectMultipleControllers(
// <GetxController>[
// SettingsController(),
// NotificationsController(),
// TaskManagerController(),
// ],
// );

runApp(
GetMaterialApp(
home: const Academia(),
Expand All @@ -61,6 +50,7 @@ class Academia extends StatelessWidget {
final userController = Get.put(UserController());
Get.put(NotificationsController());
Get.put(SettingsController());
Get.put(TodoController());

// Prompt for permission
AwesomeNotifications().isNotificationAllowed().then((value) {
Expand Down
40 changes: 40 additions & 0 deletions lib/tools/todo/controllers/todo_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import 'package:academia/exports/barrel.dart';
import 'package:get/get.dart';

class TodoController extends GetxController {
RxList<Todo> todos = <Todo>[].obs;

@override

/// Opens the database
/// Initializes the [todos] if they exist in the database
void onInit() {
// Read all todos
TodoModelHelper().queryAll().then(
(value) => todos.value = value.map((e) => Todo.fromJson(e)).toList());
super.onInit();
debugPrint("[+] Todo initialized successfully");
}

/// Adds a todo specified by [newTodo] to the local db
Future<void> createTodo(Todo newTodo) async {
await TodoModelHelper().create(newTodo.toJson());
TodoModelHelper().queryAll().then(
(value) => todos.value = value.map((e) => Todo.fromJson(e)).toList());
}

/// Deletes both from db and [todos] a todo specified by [id]
Future<void> deleteTodo(int id) async {
todos.removeWhere((element) => element.id == id);
await TodoModelHelper().delete(id);
update();
}

/// Deletes both from db and [todos] a todo specified by [id]
Future<void> updateTodo(Todo update) async {
todos.removeWhere((element) => element.id == update.id);
await TodoModelHelper().update(update.toJson());
TodoModelHelper().queryAll().then(
(value) => todos.value = value.map((e) => Todo.fromJson(e)).toList());
}
}
23 changes: 14 additions & 9 deletions lib/tools/todo/models/todo_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ class Todo {
final String name;
final DateTime date;
final String notificationTime;
final String notificationFrequency;
final bool notificationFrequency;
final String color;
final String description;
final bool complete;
final DateTime dateAdded;
final DateTime? dateCompleted;

Todo({
this.id,
Expand All @@ -19,19 +20,22 @@ class Todo {
required this.description,
required this.complete,
DateTime? dateAdded,
this.dateCompleted,
}) : dateAdded = dateAdded ?? DateTime.now();

factory Todo.fromJson(Map<String, dynamic> json) {
return Todo(
id: json['id'] as int?,
name: json['name'] as String,
date: DateTime.parse(json['date']),
notificationTime: json['notificationTime'],
notificationFrequency: json['notificationFrequency'] as String,
notificationTime: json['notification_time'],
notificationFrequency:
(json['notification_frequency'] ?? 0) == 1 ? true : false,
color: json['color'] as String,
description: json['description'] as String,
complete: json['complete'] as bool,
dateAdded: DateTime.parse(json['dateAdded']),
complete: (json['complete'] ?? 0) == 0 ? false : true,
dateAdded: DateTime.parse(json['date_added']),
dateCompleted: DateTime.tryParse(json['date_completed'] ?? ""),
);
}

Expand All @@ -40,12 +44,13 @@ class Todo {
'id': id,
'name': name,
'date': date.toIso8601String(),
'notificationTime': notificationTime,
'notificationFrequency': notificationFrequency,
'notification_time': notificationTime,
'notification_frequency': notificationFrequency == true ? 1 : 0,
'color': color,
'description': description,
'complete': complete,
'dateAdded': dateAdded.toIso8601String(),
'complete': complete == true ? 1 : 0,
'date_added': dateAdded.toIso8601String(),
'date_completed': dateCompleted?.toIso8601String(),
};
}
}
83 changes: 42 additions & 41 deletions lib/tools/todo/models/todo_model_helper.dart
Original file line number Diff line number Diff line change
@@ -1,71 +1,72 @@
import 'package:academia/storage/storage.dart';
import 'todo_model.dart';
import 'package:academia/exports/barrel.dart';
import 'package:sqflite/sqflite.dart';

class TodoModelHelper {
class TodoModelHelper implements DatabaseOperations {
static final TodoModelHelper _instance = TodoModelHelper._internal();

factory TodoModelHelper() {
return _instance;
}

TodoModelHelper._internal();

// Register the table schema
void registerModel(Database db) {
db.execute('''
CREATE TABLE IF NOT EXISTS todos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
DatabaseHelper().registerModel('todos', '''
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
date TEXT NOT NULL,
notificationTime TEXT NOT NULL,
notificationFrequency TEXT NOT NULL,
notification_time TEXT NOT NULL,
notification_frequency TEXT NOT NULL,
color TEXT NOT NULL,
description TEXT,
complete INTEGER NOT NULL,
dateAdded TEXT NOT NULL
)
date_added TEXT NOT NULL,
date_completed TEXT
''');

return _instance;
}

// Insert a new Todo
Future<int> insert(Todo todo) async {
TodoModelHelper._internal();

@override

/// Inserts a new todo on the local database specified by [data]
Future<int> create(Map<String, dynamic> data) async {
final db = await DatabaseHelper().database;
return await db.insert(
final id = await db.insert(
'todos',
todo.toJson(),
data,
conflictAlgorithm: ConflictAlgorithm.replace,
);

debugPrint("[+] Todo written successfully");
return id;
}

// Get all Todos
Future<List<Todo>> getAllTodos() async {
final db = await DatabaseHelper().database;
final List<Map<String, dynamic>> maps = await db.query('todos');
@override

return List.generate(maps.length, (i) {
return Todo.fromJson(maps[i]);
});
/// Queries for all todos stored in the local database
Future<List<Map<String, dynamic>>> queryAll() async {
final db = await DatabaseHelper().database;
final users = await db.query('todos');
return users;
}

// Update a Todo
Future<int> update(Todo todo) async {
@override
Future<int> update(Map<String, dynamic> data) async {
final db = await DatabaseHelper().database;
return await db.update(
'todos',
todo.toJson(),
where: 'id =?',
whereArgs: [todo.id],
);
return await db
.update('todos', data, where: 'id =?', whereArgs: [data['id']]);
}

// Delete a Todo
@override

/// Deletes a todo specified with id [id]
Future<int> delete(int id) async {
final db = await DatabaseHelper().database;
return await db.delete(
'todos',
where: 'id =?',
whereArgs: [id],
);
return await db.delete('todos', where: 'id =?', whereArgs: [id]);
}

@override
Future<void> truncate() async {
final db = await DatabaseHelper().database;

await db.execute('DROP TABLE todos');
}
}
2 changes: 2 additions & 0 deletions lib/tools/todo/todo.dart
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export 'todo_home_screen.dart';
export 'models/models.dart';
export 'controllers/todo_controller.dart';
101 changes: 58 additions & 43 deletions lib/tools/todo/todo_home_screen.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:academia/exports/barrel.dart';
import 'package:academia/tools/todo/todo_view_page.dart';
import 'package:get/get.dart';

class TodoPage extends StatefulWidget {
const TodoPage({super.key});
Expand All @@ -9,55 +10,69 @@ class TodoPage extends StatefulWidget {
}

class _TodoPageState extends State<TodoPage> {
final todoController = Get.find<TodoController>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Agenda"),
actions: [
IconButton(onPressed: () {}, icon: const Icon(Ionicons.menu)),
],
),
body: SafeArea(
minimum: const EdgeInsets.symmetric(horizontal: 4),
child: Column(
children: [
SizedBox(
height: 40,
child: ListView(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
children: [
FilterChip.elevated(
label: const Text("Today"),
selected: true,
onSelected: (value) {},
),
const SizedBox(width: 8),
FilterChip.elevated(
label: const Text("All"),
selected: false,
onSelected: (value) {},
),
const SizedBox(width: 8),
FilterChip.elevated(
label: const Text("Tommorrow"),
selected: false,
onSelected: (value) {},
),
const SizedBox(width: 8),
FilterChip.elevated(
label: const Text("This Week"),
selected: false,
onSelected: (value) {},
),
const SizedBox(width: 8),
FilterChip.elevated(
label: const Text("This Month"),
selected: false,
onSelected: (value) {},
child: CustomScrollView(
slivers: [
SliverAppBar(
title: const Text("Agenda"),
actions: [
IconButton(onPressed: () {}, icon: const Icon(Ionicons.menu)),
],
),
SliverToBoxAdapter(
child: SizedBox(
height: 40,
child: ListView(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
children: [
FilterChip.elevated(
label: const Text("Today"),
selected: true,
onSelected: (value) {},
),
const SizedBox(width: 8),
FilterChip.elevated(
label: const Text("All"),
selected: false,
onSelected: (value) {},
),
const SizedBox(width: 8),
FilterChip.elevated(
label: const Text("Tommorrow"),
selected: false,
onSelected: (value) {},
),
const SizedBox(width: 8),
FilterChip.elevated(
label: const Text("This Week"),
selected: false,
onSelected: (value) {},
),
const SizedBox(width: 8),
FilterChip.elevated(
label: const Text("This Month"),
selected: false,
onSelected: (value) {},
),
],
),
),
),
SliverFillRemaining(
hasScrollBody: true,
child: Obx(
() => ListView.builder(
itemCount: todoController.todos.length,
itemBuilder: (context, index) => ListTile(
title: Text(todoController.todos[index].name),
),
],
),
),
),
],
Expand Down
Loading

0 comments on commit a28c98f

Please sign in to comment.