- Lab
- Core Tech

Guided: Build a Habit Tracker in Kotlin
In this Guided Code Lab with Kotlin, you will build a Habit Tracker application. The objective is to develop a functional habit-tracking system, allowing users to add habits, mark them as completed, and view their progress. Your journey in this lab will provide practical insights into Kotlin fundamentals, data handling using data classes, user interaction through a console-based interface, object-oriented programming principles, and the compilation and testing of Kotlin code. By the end of the lab, you'll have a tangible understanding of Kotlin programming, enabling you to build simple yet effective applications.

Path Info
Table of Contents
-
Challenge
Introduction
Scenario
Imagine you have a list of habits you want to track, such as drinking enough water, exercising daily, or reading for at least 30 minutes. However, keeping track of these habits manually can be tedious and prone to errors. That's where a Habit Tracker application comes in handy! With this application, you can add your habits, mark them as completed when you accomplish them, view your progress, and even delete habits you no longer wish to track.
Code Lab
In this Guided Code Lab, you will delve into the realm of Kotlin programming to create a Habit Tracker application from the ground up. Your focus will be primarily on the
HabitTracker.kt
file, where you'll implement essential functions crucial for constructing the Habit Tracker.Completing this Kotlin Habit Tracker lab will involve mastering the following key concepts:
Kotlin Basics: Gain proficiency in fundamental Kotlin syntax and language features.
Data Handling: Learn to model structured data using Kotlin data classes. Implement date handling using
java.time.LocalDate
.User Interaction: Develop a console-based user interface for habit tracking. Manage user input and execute corresponding actions.
Before you begin, here are some key points:
- Your task involves implementing code in the
Habit.kt
andHabitTracker.kt
files. - If you encounter any challenges along the way, feel free to consult the
solution
directory. - To simplify the process, comments are included to help you find the necessary changes for each task according to the step you're working on.
For instance, if you're currently on Step 3, you can locate the relevant changes by finding// T0-DO Step 3
in the file.
- Your task involves implementing code in the
-
Challenge
Define the Habit Data Class
To build your Habit Tracker, you will need to understand data classes and learn how to leverage them to efficiently store and manage data. Your goal is to create a data class to represent habit data. Get started by understanding what a data class is and how it can simplify the process of storing your habit-related information.
### Data ClassIn Kotlin, a data class is a special class designed to hold data in a concise and effective way. It comes with built-in functionality, such as automatic generation of common methods like
toString()
,equals()
, andhashCode()
. This makes it an ideal choice for modeling simple data structures where the focus is on the data itself.Consider an example where you have a
Task
data class with aMutableList
property to represent a list of subtasks:data class Task(val title: String, val subtasks: MutableList<String>)
You'll utilize the features of data classes to streamline the creation and management of habit data.
Next, you will create a data class named
Habit
to represent information about habits. A habit typically has aname
,startDate
, and a list ofcompletedDates
.Great job! Next, you will understand about the
HabitTracker
class and build a CLI Menu. -
Challenge
Explore the `HabitTracker` Class & Construct the Menu
Now review the current setup and the files which you will be working with.
The
Main.kt
FileThis file acts as an entry point, instantiating the
HabitTracker
class and calling thestart()
function ofHabitTracker
class.fun main() { val habitTracker = HabitTracker() habitTracker.start() }
The
HabitTracker.kt
FileThis file contains the code for user interactions and habit management.
Private Variables
Within the
HabitTracker
class, you have two private properties:-
habits
: This is a mutable list which will be used to store habits. -
scanner
: This is an instance of Scanner for handling user input in your program.
class HabitTracker { private val habits = mutableListOf<Habit>() private val scanner = Scanner(System.`in`)
The
start
FunctionThis function provides users with a Menu Interface and captures the user inputs. Inside the
while
loop , the application continuously displays a menu to the user. You will use thewhen
construct to create a switch-case statement.The
when
ExpressionIn Kotlin, the
when
expression serves as a more powerful and flexible alternative to traditional switch-case statements found in other programming languages. It allows you to match a value against multiple cases and execute different code blocks based on the matching case.Example :
println("Please enter a number (1-3): ") when (scanner.nextInt()) { 1 -> println("You entered 1") 2 -> println("You entered 2") 3 -> println("You entered 3") else -> println("Invalid Input") }
In the above example, the
else
option in awhen
expression acts as the default case, executing when none of the other option match. This helps handle unexpected inputs or conditions gracefully.
Now you will learn about the available options and their respective methods for the Habit Tracker :
1. Add Habit
addHabit()
: This function will prompt the user to input details about a new habit they want to track. It will then add this habit to the list of habits stored within theHabitTracker
instance.2. Mark Habit Completed
markHabitCompleted()
: This function will display a list of habits that the user can mark as completed. The user will select a habit from the list, and the function will mark it as completed.3. View Progress
viewProgress()
: This function offers users an insight into their habit-tracking journey. It presents a summary of habits along with the count of days each habit has been completed since its inception.4. Delete Habit
deleteHabit()
: This function will allow users to remove a habit from their list of tracked habits. It will prompt the user to select the habit they want to delete and then remove it from the list.5. Exit
This option exits the Habit Tracker gracefully.
Now you will design the Menu for the Habit Tracker. In the next steps, you are going to implement the habit tracker functions in order to have a fully functioning Habit Tracker.
-
-
Challenge
Implement Add Habit
In this step, you will implement the
addHabit
method within theHabitTracker
class. This method prompts you to enter the name of a new habit, creates a habit instance with the current date and an empty list of completed dates, and adds the habit to the list.You are going to use
Scanner
in order to get the user input. Next, you will learn about Scanners.Scanner
Scanners allow you to read input from the standard input stream (System.in). You can use them to retrieve various types of data, such as strings, numbers, or entire lines of text, entered by the user during program execution.
Some commonly used methods include:
next()
: Reads the next token (a word) from the input.nextInt()
: Reads the next token as an Int.nextLine()
: Reads the next line of input as a string.
Here is an example:
val name = scanner.next()
In the above example the user input from the console will be assigned to variable
name
.The function
addHabit()
is responsible for allowing users to add a new habit to the Habit Tracker application. Now, you will complete the implementation of this method. In this step, you have learned how to usescanner
to get the console input, create an object, and insert it into a mutable list.Next, you're going to implement the
markHabitCompleted
method, which will allow you to add tracking information to a habit regarding it's completion. -
Challenge
Implement Mark Habit Completed
In this step, you will implement the
markHabitCompleted
method within theHabitTracker
class. This method enables users to mark a habit as completed for the current date.
Before you start the implementation, you will need to understand how you can retrieve an item from the list.
The Indexing operator
[]
operator helps to retrieve an element at a specific position within a collection, such as arrays, lists, and maps, using their indices or keys.Example:
val element = list[index]
Here, index represents the position of the element you want to access in the list. The indexing operator allows you to specify this position within the square brackets and the element at that position is returned.
Similarly in maps, the indexing operator [] is used to access values based on their keys.
val myMap = mapOf("name" to "John", "age" to 30) println(myMap["name"]) // Output: "John"
You will now explore the
isEmpty()
method as well.
In Kotlin,isEmpty()
is a method accessible on collections like lists, sets, and maps. It enables you to determine whether the collection holds any elements or if it's empty.Example:
val myList = listOf<Int>() println(myList.isEmpty()) // Output: true
Now you will implement the
markHabitCompleted
method which provides users with the ability to mark a habit as completed, ensuring accurate tracking of their progress within the Habit Tracker application. In this step, you have learned about the indexing operator[]
andisEmpty()
method available in collections.Next you're going to implement the
viewProgress
method which allows you to keep track of the all the habits that you're following and see the progress of each habit. -
Challenge
Implement viewProgress Method
In this step, you are going to complete the
viewProgress
method within theHabitTracker
class. If there are existing habits, the program prints the progress of each habit, indicating the number of completed days out of the total days since the habit's start.
Next, you will learn how you iterate over a list using the
forEach
loop.The
forEach
LoopThe
forEach
loop in Kotlin provides a convenient way to iterate over elements in a collection and perform specific actions for each element.Example:
collection.forEach { element -> // Code to be executed for each element println("Element Value ${element}") }
For each element in the
collection
, the lambda expression{ element -> println("Element Value ${element}") }
is executed. The current element is represented by the parameterelement
within the lambda expression.
Now, you will understand the code of
viewProgress
function.The
Habit
object comprises variables such as name,startDate
, andcompletedDate
, all of which are stored within a list calledhabits
.The subsequent code snippet is responsible for printing the habit's name alongside the number of days it has been completed since its initiation:
habits.forEach { habit -> println("${habit.name}: ${habit.completedDates.size} completed out of ${calculateDaysSinceStart(habit)} days") }
Here's what happens within this snippet:
-
completedDates.size
yields the count of days the habit has been marked as completed. -
calculateDaysSinceStart
method computes the number of days since the habit commenced.
The
calculateDaysSinceStart
FunctionThis function calculates the number of days it has been since the habit has started.
Consider a simple scenario: To determine the duration of a habit, suppose you commenced the habit on the 10th Jan 2024 and the current date is the 14th Jan 2024.
days = 14 - ( 10 + 1 ) = 5 days ( 10th , 11th, 12th , 13th, 14th )
The addition of 1 to the sum is necessary to incorporate the present day into the calculation.
This logic will work if your start date and end date are in same month. Since the habit can span multiple months, you will need to use better logic to implement your calculation.
Next, you will understand about
LocalDate
class which will be helpful for implementing thecalculateDaysSinceStart
method.The
LocalDate.now()
FunctionIn Kotlin,
LocalDate.now()
is a function call that returns the current date in the local time zone. It retrieves the date without the time component, representing the current day, month, and year.Following that,
.toEpochDay()
is a method used to convert aLocalDate
object to the number of days since January 1, 1970 (the Unix epoch). It returns a long value representing the number of days elapsed since that reference date.Together,
LocalDate.now().toEpochDay()
provides a convenient way to obtain the current date and convert it into a standardized representation of days since the Unix epoch.Here you will perform the calculation again using Epoch date ( January 1, 1970 ) as a reference:
days = (Epoch date to 14th Jan) - (Epoch date to 10th Jan) + 1 days = 19737 - 19733 + 1 days = 5
This logic will work to find days between multiple months.
Now, you will use this understanding to complete your
calculateDaysSinceStart
method and get theviewProgress
method working.To calculate the
calculateDaysSinceStart
, you will need to subtract the present date epoch from the epoch date since the habit has started. In this step, you have learned abouttoEpochDay()
which helps to convert a LocalDate object into the number of days since the epoch.Next, you'll be tasked with implementing the
deleteHabit
method, enabling you to remove habits that are no longer of interest to you. -
-
Challenge
Implement deleteHabit Method
There is a possibility that you no longer want to pursue a certain habit. In this step, you are going to add support for habit deletion.
In Kotlin, the
removeAt(index)
function is used to remove an element from a mutable list at a specific index.When you call
removeAt(index)
on a mutable list, Kotlin removes the element at the specified index and shifts all subsequent elements to the left to fill the gap created by the removal. It also returns the removed item.Here is an example :
val removedElement = xyzList.removeAt(2)
Now you will finish the implementation of
deleteHabit()
function. Great! Now that you've successfully completed all steps you can test the Habit Tracker by clicking on the Run button on the bottom right of the Terminal tab.Alternatively you can type
java -jar out.jar
in the Terminal to run the application. -
Challenge
Conclusion and Next Steps
Congratulations on creating a working Habit Tracker application!
Throughout this course, you have learned valuable concepts and techniques in Kotlin programming while building a practical habit tracker application. You've gained insights into data classes, user input handling, list manipulation, and more, all of which are fundamental skills in Kotlin development.
Next you can improve the habit tracker with the following :
- Goal setting : Enable users to set specific goals for each habit, such as a target number of repetitions per day or week, and track their progress towards these goals.
- Streak Tracking : Implement a streak feature to track how many consecutive days users have successfully completed a habit. Streaks can be motivating and encourage users to maintain consistency.
- Custom Habit Categories: Allow users to organize their habits into custom categories or tags, such as health, fitness, productivity, etc., to better manage and prioritize their goals.
You can continue with your learning journey by going through the following courses on Pluralsight:
Keep exploring, experimenting, and honing your Kotlin skills. With dedication and practice, you'll continue to grow as a proficient Kotlin developer. Best wishes on your coding endeavors!
What's a lab?
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Provided environment for hands-on practice
We will provide the credentials and environment necessary for you to practice right within your browser.
Guided walkthrough
Follow along with the author’s guided walkthrough and build something new in your provided environment!
Did you know?
On average, you retain 75% more of your learning if you get time for practice.