Course App using Flutter

Lalita Rajpoot
7 min readAug 15, 2021

--

In this application we created online course app like udemy or anyother platforms UI by using Flutter.

Step 1: Open the VS Code.

Step 2: Create the Flutter project.

Step 3 : Next, configure the application details as shown in the below screen and click on the Next button.

Project Name: Write your Application Name.

Flutter SDK Path: <path_to_flutter_sdk>

Project Location: <path_to_project_folder>

Step 4: Now, let us check the structure of the Flutter project application and its purpose. In the below image, you can see the various folders and components of the Flutter application structure, which are going to discuss here.

.idea: This folder is at the very top of the project structure, which holds the configuration for Android Studio. It doesn’t matter because we are not going to work with Android Studio so that the content of this folder can be ignored.

.android: This folder holds a complete Android project and used when you build the Flutter application for Android. When the Flutter code is compiled into the native code, it will get injected into this Android project, so that the result is a native Android application. For Example: When you are using the Android emulator, this Android project is used to build the Android app, which further deployed to the Android Virtual Device.

.ios: This folder holds a complete Mac project and used when you build the Flutter application for iOS. It is similar to the android folder that is used when developing an app for Android. When the Flutter code is compiled into the native code, it will get injected into this iOS project, so that the result is a native iOS application. Building a Flutter application for iOS is only possible when you are working on macOS.

.lib: It is an essential folder, which stands for the library. It is a folder where we will do our 99 percent of project work. Inside the lib folder, we will find the Dart files which contain the code of our Flutter application. By default, this folder contains the file main.dart, which is the entry file of the Flutter application.

.test: This folder contains a Dart code, which is written for the Flutter application to perform the automated test when building the app. It won’t be too important for us here.

We can also have some default files in the Flutter application. In 99.99 percent of cases, we don’t touch these files manually. These files are:

.gitignore: It is a text file containing a list of files, file extensions, and folders that tells Git which files should be ignored in a project. Git is a version-control file for tracking changes in source code during software development Git.

.metadata: It is an auto-generated file by the flutter tools, which is used to track the properties of the Flutter project. This file performs the internal tasks, so you do not need to edit the content manually at any time.

packages: It is an auto-generated file by the Flutter SDK, which is used to contain a list of dependencies for your Flutter project.

flutter_demoapp.iml: It is always named according to the Flutter project’s name that contains additional settings of the project. This file performs the internal tasks, which is managed by the Flutter SDK, so you do not need to edit the content manually at any time.

pubspec.yaml: It is the project’s configuration file that will use a lot during working with the Flutter project. It allows you how your application works. This file contains:

  • Project general settings such as name, description, and version of the project.
  • Project dependencies.
  • Project assets (e.g., images).

pubspec.lock: It is an auto-generated file based on the .yaml file. It holds more detail setup about all dependencies.

README.md: It is an auto-generated file that holds information about the project. We can edit this file if we want to share information with the developers.

Step 5: Open the file pubspec.yaml and add the related packages.

Step 6: Create a contants.dart file ,will contains UI designs

import 'package:flutter/material.dart';

// Colors
const kTextColor = Color(0xFF0D1333);
const kBlueColor = Color(0xFF6E8AFA);
const kBestSellerColor = Color(0xFFFFD073);
const kGreenColor = Color(0xFF49CC96);

// My Text Styles
const kHeadingextStyle = TextStyle(
fontSize: 28,
color: kTextColor,
fontWeight: FontWeight.bold,
);
const kSubheadingextStyle = TextStyle(
fontSize: 24,
color: Color(0xFF61688B),
height: 2,
);

const kTitleTextStyle = TextStyle(
fontSize: 20,
color: kTextColor,
fontWeight: FontWeight.bold,
);

const kSubtitleTextSyule = TextStyle(
fontSize: 18,
color: kTextColor,
// fontWeight: FontWeight.bold,
);

Step 7 : Create a folder model in lib folder that will contains related data to UI . category .dart file created in model folder that contains category of courses.

class Category {
final String name;
final int numOfCourses;
final String image;

Category(this.name, this.numOfCourses, this.image);
}

List<Category> categories = categoriesData
.map((item) => Category(item['name'], item['courses'], item['image']))
.toList();

var categoriesData = [
{"name": "Marketing", 'courses': 17, 'image': "assets/images/marketing.png"},
{"name": "UX Design", 'courses': 25, 'image': "assets/images/ux_design.png"},
{
"name": "Photography",
'courses': 13,
'image': "assets/images/photography.png"
},
{"name": "Business", 'courses': 17, 'image': "assets/images/business.png"},
];

Step 8: In this file details_screen.dart contains course material data .

import 'package:course_app/constants.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';

class DetailsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: double.infinity,
decoration: BoxDecoration(
color: Color(0xFFF5F4EF),
image: DecorationImage(
image: AssetImage("assets/images/ux_big.png"),
alignment: Alignment.topRight,
),
),
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 20, top: 50, right: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
SvgPicture.asset("assets/icons/arrow-left.svg"),
SvgPicture.asset("assets/icons/more-vertical.svg"),
],
),
SizedBox(height: 30),
ClipPath(
clipper: BestSellerClipper(),
child: Container(
color: kBestSellerColor,
padding: EdgeInsets.only(
left: 10, top: 5, right: 20, bottom: 5),
child: Text(
"BestSeller".toUpperCase(),
style: TextStyle(
fontWeight: FontWeight.w600,
),
),
),
),
SizedBox(height: 16),
Text("Design Thinking", style: kHeadingextStyle),
SizedBox(height: 16),
Row(
children: <Widget>[
SvgPicture.asset("assets/icons/person.svg"),
SizedBox(width: 5),
Text("18K"),
SizedBox(width: 20),
SvgPicture.asset("assets/icons/star.svg"),
SizedBox(width: 5),
Text("4.8")
],
),
SizedBox(height: 20),
RichText(
text: TextSpan(
children: [
TextSpan(
text: "\$50 ",
style: kHeadingextStyle.copyWith(fontSize: 32),
),
TextSpan(
text: "\$70",
style: TextStyle(
color: kTextColor.withOpacity(.5),
decoration: TextDecoration.lineThrough,
),
),
],
),
),
],
),
),
SizedBox(height: 60),
Expanded(
child: Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.white,
),
child: Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(30),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Course Content", style: kTitleTextStyle),
SizedBox(height: 30),
CourseContent(
number: "01",
duration: 5.35,
title: "Welcome to the Course",
isDone: true,
),
CourseContent(
number: '02',
duration: 19.04,
title: "Design Thinking - Intro",
isDone: true,
),
CourseContent(
number: '03',
duration: 15.35,
title: "Design Thinking Process",
),
CourseContent(
number: '04',
duration: 5.35,
title: "Customer Perspective",
),
],
),
),
Positioned(
right: 0,
left: 0,
bottom: 0,
child: Container(
padding: EdgeInsets.all(20),
height: 100,
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(40),
boxShadow: [
BoxShadow(
offset: Offset(0, 4),
blurRadius: 50,
color: kTextColor.withOpacity(.1),
),
],
),
child: Row(
children: <Widget>[
Container(
padding: EdgeInsets.all(14),
height: 56,
width: 80,
decoration: BoxDecoration(
color: Color(0xFFFFEDEE),
borderRadius: BorderRadius.circular(40),
),
child: SvgPicture.asset(
"assets/icons/shopping-bag.svg"),
),
SizedBox(width: 20),
Expanded(
child: Container(
alignment: Alignment.center,
height: 56,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40),
color: kBlueColor,
),
child: Text(
"Buy Now",
style: kSubtitleTextSyule.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
)
],
),
),
),
],
),
),
),
],
),
),
);
}
}

class CourseContent extends StatelessWidget {
final String number;
final double duration;
final String title;
final bool isDone;
const CourseContent({
Key key,
this.number,
this.duration,
this.title,
this.isDone = false,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 30),
child: Row(
children: <Widget>[
Text(
number,
style: kHeadingextStyle.copyWith(
color: kTextColor.withOpacity(.15),
fontSize: 32,
),
),
SizedBox(width: 20),
RichText(
text: TextSpan(
children: [
TextSpan(
text: "$duration mins\n",
style: TextStyle(
color: kTextColor.withOpacity(.5),
fontSize: 18,
),
),
TextSpan(
text: title,
style: kSubtitleTextSyule.copyWith(
fontWeight: FontWeight.w600,
height: 1.5,
),
),
],
),
),
Spacer(),
Container(
margin: EdgeInsets.only(left: 20),
height: 40,
width: 40,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: kGreenColor.withOpacity(isDone ? 1 : .5),
),
child: Icon(Icons.play_arrow, color: Colors.white),
)
],
),
);
}
}

class BestSellerClipper extends CustomClipper<Path> {
@override
getClip(Size size) {
var path = Path();
path.lineTo(size.width - 20, 0);
path.lineTo(size.width, size.height / 2);
path.lineTo(size.width - 20, size.height);
path.lineTo(0, size.height);
path.lineTo(0, 0);
path.close();
return path;
}

@override
bool shouldReclip(CustomClipper oldClipper) {
return false;
}
}

Step 9: main.dart is the main file of this project

import 'package:course_app/constants.dart';
import 'package:course_app/details_screen.dart';
import 'package:course_app/model/category.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter_svg/flutter_svg.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Course App',
theme: ThemeData(),
home: DetailsScreen(),
);
}
}

class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.only(left: 20, top: 50, right: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
SvgPicture.asset("assets/icons/menu.svg"),
Image.asset("assets/images/user.png"),
],
),
SizedBox(height: 30),
Text("Hey Alex,", style: kHeadingextStyle),
Text("Find a course you want to learn", style: kSubheadingextStyle),
Container(
margin: EdgeInsets.symmetric(vertical: 30),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 16),
height: 60,
width: double.infinity,
decoration: BoxDecoration(
color: Color(0xFFF5F5F7),
borderRadius: BorderRadius.circular(40),
),
child: Row(
children: <Widget>[
SvgPicture.asset("assets/icons/search.svg"),
SizedBox(width: 16),
Text(
"Search for anything",
style: TextStyle(
fontSize: 18,
color: Color(0xFFA0A5BD),
),
)
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text("Category", style: kTitleTextStyle),
Text(
"See All",
style: kSubtitleTextSyule.copyWith(color: kBlueColor),
),
],
),
SizedBox(height: 30),
Expanded(
child: StaggeredGridView.countBuilder(
padding: EdgeInsets.all(0),
crossAxisCount: 2,
itemCount: categories.length,
crossAxisSpacing: 20,
mainAxisSpacing: 20,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.all(20),
height: index.isEven ? 200 : 240,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
image: DecorationImage(
image: AssetImage(categories[index].image),
fit: BoxFit.fill,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
categories[index].name,
style: kTitleTextStyle,
),
Text(
'${categories[index].numOfCourses} Courses',
style: TextStyle(
color: kTextColor.withOpacity(.5),
),
)
],
),
);
},
staggeredTileBuilder: (index) => StaggeredTile.fit(1),
),
),
],
),
),
);
}
}

--

--

Lalita Rajpoot
Lalita Rajpoot

No responses yet