Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 62 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,56 @@
<h1 align="center"> Hello, <img src="https://raw.githubusercontent.com/nixin72/nixin72/master/wave.gif"
alt="Waving hand animated gif"
height="45"
width="45" /> I'm Md Shirajul Islam</h1>
width="45" /> My Name is Septian</h1>


<!-- ABOUT THE PROJECT -->
## About The Project

LC LMS is a cutting-edge online learning management system built with Flutter, offering a seamless and engaging educational experience. This mobile app empowers users with a user-friendly interface, interactive content delivery, and robust features for efficient learning. Whether you're a student or an instructor, LC LMS provides a dynamic platform for accessing courses, submitting assignments, and fostering collaboration. Experience the future of online education with LC LMS – where innovation meets education, all in the palm of your hand.
This is a fork of [interactive_cares_lms](https://github.com/programmingwormhole/interactive_cares_lms), a Flutter-based Learning Management System (LMS).
I extended it by adding role-based authentication and dashboards for different user types:

<!-- Demo -->
## Demo Access
[![Download][Download]][Download-url]


### Built With

LC LMS, crafted with the power of Dart and Flutter, redefines online learning. This dynamic app seamlessly blends innovation and education, providing a sleek, responsive, and user-friendly experience. Whether you're a student or instructor, dive into a world of interactive courses, streamlined assignments, and collaborative tools. LC LMS is the epitome of modern education, built for the future with Dart and Flutter's cutting-edge technology.
* **Admin** 👨‍💻 – Manage courses, users, and system settings.
* **Lecturer** 👩‍🏫 – Create and manage lessons.
* **Student** 🎓 – Enroll in courses and track progress.

[![Flutter][Flutter]][Flutter-url]
[![Dart][Dart]][Dart-url]
---
<!-- Demo -->
## 🚀 Features
### 🔑 Authentication
* Login & Register with API integration
* Role-based redirection (Admin, Lecturer, Student)

### 📚 Course Management
* Featured courses, lessons, and modules
* Track lesson completion progress

### 📌 Bookmarking
* Save & manage bookmarked lessons locally

### 🎨 UI
* Flutter + GetX state management
* Material Design widgets

---
## Project Structure
```bash
lib/
├── bindings/ # GetX dependency bindings
├── controllers/ # App controllers (auth, course, lesson, bookmark)
├── core/services/ # API services (auth, shared services)
├── global_widgets/ # Reusable UI components
├── helpers/ # Helpers (requests, forms, alerts)
├── models/ # Data models (user, course, category)
├── routes/ # Route names & destinations
├── utils/ # Config, constants, colors, assets
├── views/ # Screens (Authentication, Home, Learning, etc.)
│ ├── Admin/ # NEW: Admin dashboard
│ ├── Lecturer/ # NEW: Lecturer dashboard
│ └── Student/ # NEW: Student dashboard
└── main.dart # App entry point with role-based redirection
```
---

<!-- GETTING STARTED -->
## Getting Started
Expand All @@ -37,55 +68,33 @@ Follow the below steps to run the application on your device.

1. Clone the repo
```sh
git clone https://github.com/programmingwormhole/interactive_cares_lms.git
```
2. Open Project In IDE
```sh
Android Studio, VS Code, or any other Flutter Supported IDE
git clone https://github.com/<your-username>/interactive_cares_lms.git
cd interactive_cares_lms

```
3. Get Dependencies
2. Get Dependencies
```js
flutter pub get
```
4. Run
3. Run
```js
flutter run
```

<!-- ROADMAP -->
## Key Features
- [x] Authentication using RestAPI.
- [x] Keep logged-in user by storing bearer token.
- [x] Home Screen UI
- [x] Bookmark screen with functionality
- [x] Play a lesson from the bookmark to a specific time in the video.
- [x] Enrolled Course Screen UI with functionality.
- [x] Real-time course complete progress.
- [x] Course modules
- [x] Course lesson
- [x] Previous or Next lesson system from the lesson screen
- [x] Mark as complete a lesson
- [x] After completing all lessons in a course students will get an animated dialogue to claim a certificate.
## Role Based Authentication
- On login, users are redirected to different dashboards based on their role.
- For now, roles are stored in a local mock JSON (assets/json/fake_auth.json) for testing.
- Future updates will connect to a backend API with real role-based authentication.

<!-- Package -->
## Packages
- [x] GetX (For State management)
- [x] http (For API request)
- [x] flutter_svg (To display SVG icon in the app)
- [x] lottie (To display animation in the app)
- [x] shared_preferences (To store data in local storage)
- [x] google_fonts (To use custom fonts)
- [x] carousel_slider (For creating an image slider)
- [x] page_view_dot_indicator (To show a slider dot indicator)
- [x] flutter_staggered_grid_view (To make a user-friendly grid view)
- [x] video_player & chewie (To play video from network or assets)


<!-- MARKDOWN LINKS & IMAGES -->
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
[Flutter]: https://camo.githubusercontent.com/b6d2d66adc138025ea9cdf8444cdc29a588c98d062c263f8651ba6b7ad46fef0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466c75747465722d2532333032353639422e7376673f7374796c653d666f722d7468652d6261646765266c6f676f3d466c7574746572266c6f676f436f6c6f723d7768697465
[Flutter-url]: https://flutter.dev
[Dart]: https://camo.githubusercontent.com/a0a1ad90011aa02e7e6f32be4998b8843f0884eed20b575c8a2189859550824d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646172742d2532333031373543322e7376673f7374796c653d666f722d7468652d6261646765266c6f676f3d64617274266c6f676f436f6c6f723d7768697465
[Dart-url]: https://dart.dev
[Download]: https://camo.envatousercontent.com/66cff805c4d35c74668291a51e21f978424565d9/68747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f70726f6772616d6d696e67776f726d686f6c652f656e7661746f2f6d61696e2f64656d6f2e676966
[Download-url]: https://raw.githubusercontent.com/programmingwormhole/interactive_cares_lms/main/lc_lms_demo.apk
## Roadmap
- [x]Connect role management to backend API
- [x]Add course creation for lecturers
- [x]Add course/user management for admins
- [x]Enhance student dashboard with certificates & progress tracking

---
## Credit
* Original Project [Interactive Cares LMS](https://github.com/programmingwormhole/interactive_cares_lms)
* Extended by [Septian Jauhariansyah](https://github.com/alchemista27)
5 changes: 5 additions & 0 deletions assets/mock/fake_auth.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"username": "john_doe",
"role": "student",
"token": "abc123xyz"
}
40 changes: 40 additions & 0 deletions lib/controllers/auth_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import 'dart:convert';
import 'package:get/get.dart';
import 'package:interactive_cares_lms/models/user_model.dart';
import 'package:shared_preferences/shared_preferences.dart';

class AuthController extends GetxController {
var currentUser = Rxn<UserModel>();

Future<void> login(String username, String password) async {
// Fake API call (replace with real HTTP later)
final fakeApiResponse = '''
{
"username": "$username",
"role": "${username == 'admin' ? 'admin' : username == 'lecturer' ? 'lecturer' : 'student'}",
"token": "mockToken123"
}
''';

final data = json.decode(fakeApiResponse);
currentUser.value = UserModel.fromJson(data);

// Save user data
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('user', json.encode(data));
}

Future<void> loadUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
if (prefs.containsKey('user')) {
final data = json.decode(prefs.getString('user')!);
currentUser.value = UserModel.fromJson(data);
}
}

Future<void> logout() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.remove('user');
currentUser.value = null;
}
}
6 changes: 3 additions & 3 deletions lib/helpers/request_helpers.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
class RequestHelpers {
static Map<String, String> header () {
static Map<String, String> header() {
Map<String, String> header = {
'Accept' : 'application/json',
'Accept': 'application/json',
};

return header;
}
}
}
37 changes: 24 additions & 13 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:interactive_cares_lms/controllers/auth_controller.dart';
import 'package:interactive_cares_lms/bindings/all_bindings.dart';
import 'package:interactive_cares_lms/routes/route_destinations.dart';
import 'package:interactive_cares_lms/routes/route_names.dart';
import 'package:interactive_cares_lms/utils/colors.dart';
import 'package:interactive_cares_lms/utils/config.dart';
import 'package:interactive_cares_lms/views/Admin/admin_dashboard.dart';
import 'package:interactive_cares_lms/views/Lecturer/lecturer_dashboard.dart';
import 'package:interactive_cares_lms/views/Student/student_dashboard.dart';
import 'package:interactive_cares_lms/views/Authentication/LoginScreen/login_screen.dart';

void main() {

void main() async {
WidgetsFlutterBinding.ensureInitialized();
final authController = Get.put(AuthController());
await authController.loadUser(); // ✅ allowed now
AllBindings().dependencies();
runApp(const MyApp());
}
Expand All @@ -18,15 +26,18 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
title: AppConfig.appName,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: AppColors.primary),
useMaterial3: true,
scaffoldBackgroundColor: AppColors.background,
),
getPages: Routes.destination,
initialRoute: RouteNames.initial,
);
}
}
initialBinding: AllBindings(),
home: Obx(() {
final user = Get.find<AuthController>().currentUser.value;
if (user == null) {
return LoginPage();
} else if (user.role == 'admin') {
return AdminDashboard();
} else if (user.role == 'lecturer') {
return LecturerDashboard();
} else {
return StudentDashboard();
}
}),
);

4 changes: 2 additions & 2 deletions lib/models/category_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class CategoryModel {
String title;
String icon;

CategoryModel ({required this.title, required this.icon});
CategoryModel({required this.title, required this.icon});
}

List<CategoryModel> getCategories = [
Expand All @@ -13,4 +13,4 @@ List<CategoryModel> getCategories = [
CategoryModel(title: 'Editing', icon: ImageManager.video),
CategoryModel(title: 'Development', icon: ImageManager.personalDevelopment),
CategoryModel(title: 'Math', icon: ImageManager.math),
];
];
14 changes: 13 additions & 1 deletion lib/models/user_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,32 @@ class UserModel {
String? fullName;
String? email;
String? password;
String? role; //

UserModel({
this.username,
this.email,
this.password,
this.fullName,
this.role,
});

Map<String, dynamic> toJson() {
return {
'full_name' : fullName,
'full_name': fullName,
'username': username,
'email': email,
'password': password,
'role': role,
};
}

factory UserModel.fromJson(Map<String, dynamic> json) {
return UserModel(
username: json['username'],
fullName: json['full_name'],
email: json['email'],
role: json['role'],
);
}
}
6 changes: 4 additions & 2 deletions lib/routes/route_destinations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class Routes {
GetPage(name: RouteNames.home, page: () => const BottomBarView()),
GetPage(name: RouteNames.courseLearn, page: () => const LearningScreen()),
GetPage(name: RouteNames.lesson, page: () => const LessonScreen()),
GetPage(name: RouteNames.bookmarkPlayer, page: () => const BookmarkPlayerScreen()),
GetPage(
name: RouteNames.bookmarkPlayer,
page: () => const BookmarkPlayerScreen()),
];
}
}
2 changes: 1 addition & 1 deletion lib/routes/route_names.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ class RouteNames {
static const String courseLearn = '/courseLearn';
static const String lesson = '/lesson';
static const String bookmarkPlayer = '/bookmark-player';
}
}
2 changes: 1 addition & 1 deletion lib/utils/app_urls.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ class AppUrls {
static const String apiUrl = '${AppConfig.baseUrl}/api/$apiVersion';
static Uri login = Uri.parse('$apiUrl/login');
static Uri register = Uri.parse('$apiUrl/register');
}
}
13 changes: 13 additions & 0 deletions lib/views/Admin/admin_dashboard.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import 'package:flutter/material.dart';

class AdminDashboard extends StatelessWidget {
const AdminDashboard({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Admin Dashboard")),
body: const Center(child: Text("Welcome Admin")),
);
}
}
4 changes: 2 additions & 2 deletions lib/views/HomeScreen/home_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ class HomeScreen extends StatelessWidget {
children: [
HomeAppBar(),
Padding(
padding: EdgeInsets.symmetric(
horizontal: 10, vertical: 15),
padding:
EdgeInsets.symmetric(horizontal: 10, vertical: 15),
child: Column(
children: [
SliderSection(),
Expand Down
13 changes: 13 additions & 0 deletions lib/views/Lecturer/lecturer_dashboard.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import 'package:flutter/material.dart';

class LecturerDashboard extends StatelessWidget {
const LecturerDashboard({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Lecturer Dashboard")),
body: const Center(child: Text("Welcome Lecturer")),
);
}
}
13 changes: 13 additions & 0 deletions lib/views/Student/student_dashboard.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import 'package:flutter/material.dart';

class StudentDashboard extends StatelessWidget {
const StudentDashboard({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Student Dashboard")),
body: const Center(child: Text("Welcome Student")),
);
}
}
Loading
Loading