diff --git a/lib/controllers/courses_controller.dart b/lib/controllers/courses_controller.dart index bd81b8e..0321225 100644 --- a/lib/controllers/courses_controller.dart +++ b/lib/controllers/courses_controller.dart @@ -48,4 +48,16 @@ class CoursesController extends GetxController { } return count; } + + Future<bool> createCourseTopic(CourseTopic coursesTopic) async { + final data = await CourseTopicModelHelper().create(coursesTopic.toJson()); + coursesTopics.add(coursesTopic); + return data > 0 ? true : false; + } + + Future<bool> deleteCourseTopic(CourseTopic coursesTopic) async { + final data = await CourseTopicModelHelper().delete(coursesTopic.toJson()); + coursesTopics.remove(coursesTopic); + return data > 0 ? true : false; + } } diff --git a/lib/pages/courses/course_view_page.dart b/lib/pages/courses/course_view_page.dart index a8a2caf..df2f878 100644 --- a/lib/pages/courses/course_view_page.dart +++ b/lib/pages/courses/course_view_page.dart @@ -1,5 +1,7 @@ import 'package:academia/exports/barrel.dart'; +import 'package:academia/models/core/course/course_model.dart'; import 'package:academia/models/models.dart'; +import 'package:get/get.dart'; import 'widgets/course_topic_form.dart'; class CourseViewPage extends StatelessWidget { @@ -11,6 +13,7 @@ class CourseViewPage extends StatelessWidget { @override Widget build(BuildContext context) { + final CoursesController coursesController = Get.find<CoursesController>(); return Scaffold( body: CustomScrollView( slivers: [ @@ -26,11 +29,92 @@ class CourseViewPage extends StatelessWidget { title: Text(course.unit), ), ), - const SliverPadding( - padding: EdgeInsets.all(12), + SliverPadding( + padding: const EdgeInsets.all(12), sliver: SliverFillRemaining( - child: Center( - child: Text("Hi"), + child: Obx( + () => coursesController.coursesTopics + .where((p0) => p0.course == course.unit) + .toList() + .isEmpty + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "No topics here, there are. Disappointed, I am. ${Emojis.smile_skull}", + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.headlineSmall, + ), + const SizedBox(height: 12), + Text( + "Tap the + button you must, to add a new topic", + style: Theme.of(context) + .textTheme + .bodySmall + ?.copyWith( + color: Theme.of(context).colorScheme.tertiary, + ), + ), + ], + ) + : ListView.separated( + separatorBuilder: (context, index) => + const SizedBox(height: 4), + itemBuilder: (context, index) { + final data = coursesController.coursesTopics + .where((p0) => p0.course == course.unit) + .toList()[index]; + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: Theme.of(context) + .colorScheme + .secondaryContainer, + ), + ), + child: ListTile( + title: Text(data.name), + subtitle: Text( + data.description == "" + ? "A description, there is not. Lost, it seems." + : data.description, + style: Theme.of(context).textTheme.bodySmall, + ), + leading: CircleAvatar( + child: Text((index + 1).toString()), + ), + trailing: IconButton( + onPressed: () async { + final deleted = await coursesController + .deleteCourseTopic(data); + + if (deleted) { + HapticFeedback.heavyImpact().then((value) { + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar( + content: Text( + "Deleted successfully"))); + }); + return; + } + HapticFeedback.heavyImpact().then((value) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text("Failed to delete"))); + }); + }, + icon: const Icon(Ionicons.trash), + ), + ), + ); + }, + itemCount: coursesController.coursesTopics + .where((p0) => p0.course == course.unit) + .toList() + .length, + shrinkWrap: true, + ), ), ), ) @@ -41,7 +125,9 @@ class CourseViewPage extends StatelessWidget { showModalBottomSheet( context: context, elevation: 0, - builder: (context) => const TopicForm()); + builder: (context) => TopicForm( + course: course, + )); }, child: const Icon(Ionicons.add), ), diff --git a/lib/pages/courses/widgets/course_topic_form.dart b/lib/pages/courses/widgets/course_topic_form.dart index a92270d..68f57d0 100644 --- a/lib/pages/courses/widgets/course_topic_form.dart +++ b/lib/pages/courses/widgets/course_topic_form.dart @@ -1,71 +1,100 @@ -import 'package:flutter/material.dart'; -import 'package:ionicons/ionicons.dart'; +import 'package:academia/exports/barrel.dart'; +import 'package:academia/models/core/course/course_model.dart'; +import 'package:academia/models/core/course/course_topic.dart'; +import 'package:get/get.dart'; -class TopicForm extends StatefulWidget { - const TopicForm({super.key}); +class TopicForm extends StatelessWidget { + const TopicForm({ + super.key, + required this.course, + }); + final Course course; - @override - State<TopicForm> createState() => _TopicFormState(); -} - -class _TopicFormState extends State<TopicForm> { @override Widget build(BuildContext context) { + final CoursesController coursesController = Get.find<CoursesController>(); final topicNameController = TextEditingController(); final topicDescriptionController = TextEditingController(); + final formState = GlobalKey<FormState>(); return Container( width: double.infinity, padding: const EdgeInsets.all(12), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - "Add A topic", - style: Theme.of(context).textTheme.headlineSmall, - ), - Container( - padding: const EdgeInsets.all(8), - color: Theme.of(context).colorScheme.primaryContainer, - child: Text( - "Note down topics after class to help you revise for cats and exams", - style: Theme.of(context).textTheme.bodySmall, - ), - ), - const SizedBox( - height: 22, - ), - TextFormField( - controller: topicNameController, - decoration: InputDecoration( - label: const Text("Topic name"), - hintText: "Waves and Electromagnetism", - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(4), + child: Form( + key: formState, + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + "Add A topic", + style: Theme.of(context).textTheme.headlineSmall, ), - ), - ), - const SizedBox(height: 12), - TextFormField( - controller: topicDescriptionController, - maxLines: 5, - textAlignVertical: TextAlignVertical.top, - decoration: InputDecoration( - label: const Text("Addittional Data"), - hintText: "Read topic from Scientists and Engineers book", - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(4), + Container( + padding: const EdgeInsets.all(8), + color: Theme.of(context).colorScheme.primaryContainer, + child: Text( + "Note down topics after class to help you revise for cats and exams", + style: Theme.of(context).textTheme.bodySmall, + ), ), - ), - ), - const SizedBox( - height: 22, + const SizedBox( + height: 22, + ), + TextFormField( + autovalidateMode: AutovalidateMode.onUserInteraction, + validator: (value) { + if (value!.length < 3) { + return "Please input a valid topic name"; + } + return null; + }, + controller: topicNameController, + decoration: InputDecoration( + label: const Text("Topic name"), + hintText: "Waves and Electromagnetism", + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(4), + ), + ), + ), + const SizedBox(height: 12), + TextFormField( + controller: topicDescriptionController, + maxLines: 5, + textAlignVertical: TextAlignVertical.top, + decoration: InputDecoration( + label: const Text("Addittional Data"), + hintText: "Read topic from Scientists and Engineers book", + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(4), + ), + ), + ), + const SizedBox( + height: 22, + ), + FilledButton.icon( + onPressed: () async { + if (!formState.currentState!.validate()) { + return; + } + final ok = await coursesController.createCourseTopic( + CourseTopic( + course: course.unit, + name: topicNameController.text, + description: topicDescriptionController.text), + ); + + if (ok) { + if (context.mounted) Navigator.pop(context); + } + }, + label: const Text("Add Topic"), + icon: const Icon(Ionicons.clipboard), + ) + ], ), - FilledButton.icon( - onPressed: () {}, - label: const Text("Add Topic"), - icon: const Icon(Ionicons.clipboard), - ) - ], + ), ), ); }