To-Do App with Jetpack Compose MVVM - Android Development | Stevdza - San | Skillshare

Playback Speed


  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x

To-Do App with Jetpack Compose MVVM - Android Development

teacher avatar Stevdza - San, Android Developer & UX/UI Designer

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

60 Lessons (8h 46m)
    • 1. Introduction

      3:52
    • 2. About Jetpack Compose

      6:27
    • 3. About Recomposition

      7:59
    • 4. States in Jetpack Compose

      7:23
    • 5. Compose Lifecycle

      6:37
    • 6. Side Effects

      4:55
    • 7. Layouts

      6:10
    • 8. Create the New Project

      9:39
    • 9. Add Dependencies

      3:00
    • 10. Create Model Classes

      5:51
    • 11. Introducing with ROOM Database

      4:19
    • 12. Setup ROOM Database

      14:58
    • 13. Introducing with Dependency Injection

      4:10
    • 14. Setup Dagger-Hilt

      7:00
    • 15. Introducing with Dagger-Hilt Library

      7:58
    • 16. Create ToDoRepository

      5:33
    • 17. Create SharedViewModel

      5:10
    • 18. Introducing with Navigation Component in Jetpack Compose

      5:26
    • 19. Setup Navigation Component

      19:14
    • 20. List Screen - FAB

      13:02
    • 21. List Screen - Default List App Bar

      9:39
    • 22. List Screen - List App Bar Actions

      25:15
    • 23. List Screen - Search App Bar

      17:24
    • 24. List Screen - Search App Bar - Part 2

      18:25
    • 25. Display All Tasks - Design Task Item

      14:13
    • 26. Display All Tasks - Observe Database

      12:34
    • 27. Display All Tasks - Show Empty Content

      9:48
    • 28. Display All Tasks - Create RequestState

      7:54
    • 29. Task Screen - New Task App Bar

      11:27
    • 30. Task Screen - Existing Task App Bar

      9:25
    • 31. Task Screen - Get Selected Task

      8:32
    • 32. Task Screen - Priority Drop-Down

      13:34
    • 33. Task Screen - Task Content

      11:06
    • 34. Task Screen - Display Dynamic Content

      10:22
    • 35. CRUD Operations - Limit Title Length

      4:03
    • 36. CRUD Operations - Bug Fix & Fields Validation

      8:21
    • 37. CRUD Operations - Add Task

      10:09
    • 38. CRUD Operations - Display Snack Bar

      6:40
    • 39. CRUD Operations - Update Task

      3:22
    • 40. CRUD Operations - Delete Single Task

      3:15
    • 41. CRUD Operations - Undo Deleted Task

      10:21
    • 42. CRUD Operations - Search Database

      15:22
    • 43. CRUD Operations - Delete All Tasks

      5:07
    • 44. Alert Dialog - Delete Single Task

      13:13
    • 45. Alert Dialog - Delete All Tasks

      5:15
    • 46. Introducing with DataStore

      3:06
    • 47. List Sorting - Create DataStoreRepository

      8:10
    • 48. List Sorting - Apply Sorting in a List

      11:50
    • 49. Priority Sort Drop-Down & TaskComposable FIX

      2:57
    • 50. Swipe to Delete - Implementation

      12:35
    • 51. Swipe to Delete - Animate Item Visibility

      9:56
    • 52. Splash Screen - Design Splash Screen

      7:44
    • 53. Splash Screen - Implement Splash Screen

      7:38
    • 54. Splash Screen - Animate Splash Screen

      4:26
    • 55. Navigation - Transition Animations

      14:01
    • 56. Final Word

      3:59
    • 57. Update #1 - Intercept Back Button

      7:33
    • 58. Update #2 - Code Cleanup - handleDatabaseActions()

      4:48
    • 59. Update #3 - Dependency Update and Code Cleanup

      6:15
    • 60. Update #4 - Configuration Change, SnackBar, SearchAppBar Bugs Fixed and more..

      7:46
  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels
  • Beg/Int level
  • Int/Adv level

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

164

Students

--

Projects

About This Class

Hello there and welcome to my course! In this course I'm going to teach you how to build your first Android App from scratch, using a popular UI toolkit called Jetpack Compose.

I know that lots of you have been waiting for this moment, a moment when Jetpack Compose became stable! Now it's the right time to be an Android Developer! With a Jetpack Compose building Android Apps is going to be exciting, fun and  a lot simpler then before. We are not going to need XML anymore.

Instead we are going to build our UI with a regular Kotlin file, using the full power of Kotlin programming language.  Also creating custom UI component has been easier. So you want to build a custom UI component, no problem, just start by adding a simple function annotated with @Composable annotation.

And of course how would this course look like without a real project? Our To-Do application which we are going to develop in this course will have a Single Activity and Zero Fragments. Sounds impossible? Well it isn't. So better get used to it, because that will greatly simplify the process of developing Android apps.

Now at the beginning of this course I'm going to introduce you with Jetpack Compose in general and with some of the most important concepts as well. You will learn everything about the Lifecycle of a single composable and how Compose Compiler is doing all the hard work for you behind the scenes.

In this course we are going to use some of the most important Android Architecture components like:

- ROOM Database: To save and read the data from a local database, plus we are going to write some custom SQL queries as well.

- Compose Navigation: So we can navigate between our Screen Composables. And At the end of the course you will also learn how to add some beautiful transition animations as well.

- ViewModel: Which will contain all the logic needed to work with our app.

- Preference DataStore: To persist a simple key-value pairs.

- And you'll learn about a popular dependency injection library called Dagger-Hilt. You will see how to inject a ViewModel with different  dependencies without needing to create a ViewModel Factory.

By default our application will support Dark Mode as well, and you will learn how easy it is to have two different themes of your app with a Jetpack Compose. You will also learn how to build your own custom UI components.We will use some of the most popular material components along with a Scaffold, which is an amazing composable function that uses SLOT API, to place all your UI components in the place they belong by the rules of material design documentation.

To-Do app on which we are going to work on will have an animated Splash Screen, as some other components in our app. Also an Animated Swipe to Delete functionality which will allow us to easily remove an item from the list. Along with that we will add a safety feature called UNDO deleted item, which will display a SnackBar whenever we delete an item from the list, so we can get it back by one click. You will learn planty of other things related to the new way of developing Android Apps.

And finally this course will be constantly updated with new videos whenever needed. Whenever we find a bug in our app, then I'm going to record a video about it and we are going to fix it together. Plus you'll be in contact with me throughout this whole course, and you can always ask me a question related to this course and even suggest some code cleanup for the project if  you are skilled enough to find it.

Overall this is going to be quite a journey.

So what are you waiting my friend, let's start learning!

Project Source Code:
https://github.com/stevdza-san/To-Do-Compose

Meet Your Teacher

Teacher Profile Image

Stevdza - San

Android Developer & UX/UI Designer

Teacher

Class Ratings

Expectations Met?
  • Exceeded!
    0%
  • Yes
    0%
  • Somewhat
    0%
  • Not really
    0%
Reviews Archive

In October 2018, we updated our review system to improve the way we collect feedback. Below are the reviews written before that update.

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Introduction: Hello there and welcome to my course in these squares. I'm going to teach you how to build your first Android app from scratch Using Popular UI toolkit called the jet pre-compose. I know that lots of you have been waiting for this moment, a moment when they get decomposed, became stable, and they're now is the right time to be an Android developer with jetpack compose, building Android apps is going to be exciting, fun and the a lot simpler than before. We are not going to need the XML anymore. Instead, we are going to build our UI with the regular causing file using the full power of Kotlin programming language, also creating a custom UI component that has never been easier. So while you want to build a custom UI component and no problem, just start by adding a simple function annotated the width they're composable annotation. And of course, how would this course I look like without a real project? So our to-do application that we are going to develop in this course will have a single activity and the 0 fragments sounds impossible. Well it isn't. So a better get used to it because that will greatly simplify the process of developing Android apps. Now at the beginning of this course, I'm going to introduce you with jetpack composing general, and with some of the most important concepts as well, you will learn everything about the lifecycle of a single composable and the how composers a compiler is doing all the hard work for you behind the scenes now in this course, so we are going to use some of the most important Android architecture components like Room database to save and read the data from a local database. Plus, we're going to write some custom SQL queries as well. Then we have a composed navigations so we can navigate between our screen composable and the at the end of the scores. So you will also learn how to add some are beautiful transition animations as well. Next, we have our view model will contain all the logic and needed to work with our app. Then we have our preference data store to persist a simple key and value pairs. And you will learn about the popular dependency injection library called the dagger hilt. You will see how to inject a ViewModel with a different dependencies without needing to create a ViewModel Factory. So by default, our application and we'll support dark mode as well. And the you will learn how easy it is to have a two different themes of your app with our jet decompose. Also, you will learn how to build your own custom UI components. And we will use some of the most important material components, along with the scaffold is an amazing guy composable function that uses slots API to place all your UI components in the place they belong by the rules of material design documentation. Now, Todo application on which we are going to work on a will have an animated splash screen as some other components in our app as well. Also an animated the swipe to delete functionality, which will allow us to easily remove an item from the list. And then along with that, that we will add a safety feature called the undo deleted item, which will display a snack bar whenever we delete an item from the list. So while we can get it back just by one click, now, you will learn are plenty of other things related to the new way of developing Android apps. And the finally, this course will be constantly updated with the new videos whenever needed. So whenever we find a bug in our application, then I'm going to record a video about it and that we are going to fix that together. Plus, you will be in contact with me throughout this whole course. And that you can always ask me a question related to this course and even suggest some are called cleanup for the project if you are a skilled enough to find it overall, this is going to be quite a journey. So what are you waiting for, my friend, I'll start learning. 2. About Jetpack Compose: Hi, hello there and welcome back. In this video, I'm going to introduce you with the jetpack compose. So jetpack compose is Android, so modern toolkit for building a native UI, it simplifies and the accelerates UI development on Android by bringing your application store life with a less code. Our whole tools and intuitive Kotlin APIs, it makes a building Android UI fun, faster and easier. Compose allows you to do more with less code compared to the traditional view system. And the code you're writing is a written only in Kotlin rather than having it split between aquatic and XML. So while we decompose, you'll build the small stateless components that are not tied to a specific activity or fragment. And that makes them easy to reuse and test in compose state is the explicit and passed to the composable. That way there is only one single source of truth for the state and making it the encapsulated and they're decoupled. Then as app state changes, your UI automatically updates. So compose is compatible with all your existing code. You can call composed code from our views and the views from compose. Most common libraries like a Navigation View Model and Katlyn coroutines work with compose so you can start adopting when and where you want. So what the traditional Android view hierarchy is represented as a tree or a UI widgets. And there is the state of the app changes because of the things like a user interactions. For example, the UI hierarchy needs to be updated to display the current data. So the most common way of updating the UI is to walk the tree using functions like a findViewByID. And that changed nodes by calling methods like buttons, text, images, set, image, bitmap and so on. And these methods change the internal state of the widget. However, manipulating views manually increases the likelihood of errors. And if a piece of a data is rendered in a multiple places, It's very easy to forget to update one of the views that they're shows it. It's also easy to create illegal states when a two updates conflict in an unexpected way. For example, an update to my try to set the value of a node that was removed from the UI. And the, over the last several years, the entire industry, he has started shifting to a declarative UI model, which are greatly simplifies the engineering associated with a building and updating a user interfaces. So this technique works by conceptually regenerating the entire screen from scratch and then applying only the necessary changes. This approach avoids the complexity of our manual updating a stateful view hierarchy. They're now in a jetpack compose. You define your UI by writing composable functions. Composable functions are just a regular Kotlin functions annotated with decomposable annotation. This annotation will inform composed compiler that the annotated function is going to optionally take some data and emit a UI. The data is passed through the parameters of the annotated function, which allows you to display a dynamic content in your UI just by passing a state to your composable function. Sowell, for example, when you are observing the state some value and whenever that value changes, then you are composable. Function r will be updated with the new value immediately without you needing to call functions like setText, set even drawable, and others to change the state of your UI, you need to forget about that because we budget, they compose, we are working with our state and our application itself should react automatically to state changes. So that's how simple it is. Of course a, you will see all of that in practice in the future videos of this course. And therefore, some of the most popular UI components inside the Android app, like a text button, floating action button, text field and so on. There are already existing composable functions which you can use out-of-the-box. Also, you can inspect the source code of those are composable functions and see how they are actually made behind the scenes. Composable functions so it doesn't return anything and compose functions that emit UI do not need to return anything because they describe the desired screen state instead of constructing UI widgets. Now, in the traditional view system, we initialize the UI by inflating an XML layout file and each widget maintains its own internal state and exposes getters and setters that allows the app logic to interact with a widget In the composer. On the other hand, we have a declarative approach where our widgets are relatively stateless and do not expose a setter or getter functions. In fact, that widgets are not exposed as objects. You update the UI by calling the same composable function with a different arguments. This makes it easy to provide this data to architectural or patterns like ViewModel. So what the application logic provides data to the top-level composable function. And that function uses the data to describe the UI by calling other composable and passes the appropriate data to those composable down in the composable hierarchy, of course, now, when the user interacts with the UI, the UI raises events such as an onclick. Those events should notify the app logic, which can then change the application state. So when the state changes, the composable functions are called again with the new data, and this causes the UI elements to be redrawn. And this process of a redrawing a composable functions is a calling a recomposition. So the user interacted with the UI element, causing any event will be triggered the app logic response to that event, then the composable functions are automatically called again with a new parameters if necessary, because the composable functions are written in Kotlin instead of XML, they can be as dynamic as other Kotlin code. For example, suppose you want to build a UI that the greets a list of users in this example here, this function takes a list of names and that generates a greeting for each user. So composable functions can be quite sophisticated and you can use if statements to their side. If you want to show a particular UI element or not, you can use a loose as well, so you have the full flexibility of the underlying language. This power of flexibility is one of the key advantage of or just decompose. So that'll be all for this introduction video with digital compose, and they're in the next video, I'm going to talk more about the one important concept called the recomposition. 3. About Recomposition: Hello there and welcome back. In this video, I want to talk more about the concept of a recomposition, energetic compose. Now before we continue, I need to introduce you with a two important concepts, initial composition and the recomposition. So initial composition is when you display your UI by calling composable functions for the first time. And they're recomposition is when you are composable functions recompose or the spleen, the UI when the state of your app changes. Now in the traditional view system, when we want to change the value of a view, for example, let's say a TextView, then we would call a setter on that view to change its internal state. On the other hand, in compose, It's a little different. When we want to change the internal state of a composable, we just call that composable function I again with the new data. And thereby doing so, the UI which was made by that composable will be redrawn and the we'll be able to see the change. Now, let's take a one composable function as an example. Here you can see that we have declared that one composable function named the mike composable. And inside we have one button, and inside that button we have a text, and the text value will be changed whenever we click on the button, basically our text is observing that the variable which we have declared, and whenever it's changed, a recomposition that will trigger and we will see a new value in our text. Now, that variable is using this, remember composable in the purpose of that remember is exactly what its name says to remember something. So a value computed by remember is a saved in a composition during initial composition in the saved value is returned during a recomposition. However, if we don't use remember, then our texts will not be updated on a recomposition. And the reason is simple because the value or wouldn't be saved. Also, remember, can be used to store both the mutable and immutable objects. Next there you can see that we are using is something called the mutable state off to set the initial value of our variable. Now with this, our variable is no longer a regular variable. Now it's a state. And a state can be observed from our composable functions and it can notify its observers whenever its value changes. So if we check the official documentation for immutable state of D&I, you'll see that it's basically a single value holder a which can be observed by the compose. Now after that, whenever we click our button, my value variable a will be updated. In the new value will be saved. Plus, since our variable is now a state which is absurd by their compose, then our texts will be updated immediately whenever we click a button. And when I say that the new value will be saved, and it means that when a recomposition occurs, that value will survive. Now, recomposing the entire UI tree can be expensive because it uses the computing power and the battery life. So a Jetta composers solve this problem with something that's called the intelligent, the recomposition. Now let's take that example from before and the edit tool log statements so we can observe what the log will be executed when a recomposition triggers. So well, when we run this composable for the first time, both of those logs will be printed, but when we press a button, only the second log will be printed. Now, that's the proof of any intelligent to recomposition. In this case, only button's content lambda will recompose and thus we will print the second log only. Now, you might already know that, but we can call composable functions inside other composable functions as well. Now let's say we have one composable function which contains two more composable. If only one of those two functions inside changes its state, that means that any intelligent the recomposition will update only the UI, which is connected only with that composable which state has been changed. And they went to compose the recomposes based on the new inputs. It only calls the functions or lambdas that might have changed and it will skip the rest. So base keeping all functions or lambdas Neta haven't changed, composed can recompose efficiently. Now, there are a number of things to be aware of when you're programming compose. So the first thing, composable functions, they can execute in any order. And if you look at this Cold War, a composable function, you might assume that the code is run in the order it appears, but this isn't necessarily true. So if a composable function contains calls to other composable functions, then those functions I might run in any order. So composes a has the option of recognizing that some UI elements are a higher priority than others and that drawing them first. Now let's take one composable function as an example. Calls to start screen, middle screen and N screen might happen in any order. This means that you cannot, for example, have a Status screen set some global variable, which is a side effect. And the heavier middle screen take advantage of that change. Instead that each one of those functions need to be self-contained. The second thing about the Data Composer, which you should be aware of is that a composable functions can execute in a parallel, so composed can optimize the recomposition by running composable functions in parallel. And this will lead composed take advantage of multiple cores. This optimization means that composable function might execute within a pool of a background threads. If a composable function calls a function on a view model, then a composer might call that function from several threads in the same time. The next thing that you should be aware of when you're working with a jetpack compose is that the recomposition skips as many composable functions and landless as possible, so well, when a portion of your UI are invalid, composer does its best to recompose and just the portions that needs to be updated. And every composable function and lambda might recompose by itself. Here is one example that demonstrates how recomposition can skip some elements when a rendering list. This is also another example from which you can see that an intelligent recomposition will make sure to update only the parts of the code which is necessary. By doing that, it can save a lot of resources. Also, you can pause this video to think about this code and try to understand it. The next thing that you should be aware of when working with a compose is that the recomposition is optimistic and there may be cancelled. Savoir recomposition starts whenever composer things then the perimeters of our composable might have changed. A recomposition is an optimistic, which means that compose expects to finish recomposition before the parameters change again, and the EFA parameter does change it before recomposition finishes, then a composer might cancel the recomposition and they're restarted with the new perimeter. The final thing that you should be aware of when working with the Jetta compose is that composable functions some might run quite frequently. In some cases, a composable function might run for each frame of a UI animation. For example, if a function performs expensive operations like a reading from a device storage, then the function can cause a UI junk. For example, if you are widget that tries to read the device settings, it could potentially read those settings hundreds of times of a second, which is a disaster for your application performance. So if you are composable function needs the data, it should they find parameters for the data. And you can then move expensive work to another thread outside of a composition and pass the data to compose using immutable state of oral live data. Okay, so that was a lot of information for you to process. I think that we have covered here a lot of important information regarding the recomposition. Also, it's quite useful for you to know all of this theory about the jet decompose because later when you start working on your own projects. So using a Jetta compose, whenever you come across on summer bag or something, then you can think about how Jetta compose actually works. And then that might help you to find a solution. And in the next video, we are going to continue exploring some other concepts like a state. So for this video, that'll be all. 4. States in Jetpack Compose: Hello there and welcome back. In this video, I'm going to talk more about the concept of states in the agenda compose. So a state is one of the most important concepts in a compose. And the First, let's start with a definition. So what is a state in compose? Well, a state is any value that can change over time. For example, it may be a value stored in a room database, our variable on our class, or even that current value read from your device's sensor, for example. So in compose, the UI is immutable, which means that there is no way to update the UI after it has been drawn. You can control however, is the state of your UI. And there every time the state of your UI changes, compose a recreates the parts of the UI tree that they have changed. That process is called the recomposition, and we have already talked about it now, composable so it can accept the state and expose events. And the state is any value that can change over time and event. We'll notify a part of a program that something has happened. For example, a TextField assets of value, which is a state and exposes a call back on value change, which represents any event that will be triggered whenever we type even a single character in our text field. Now in this example here you can see that we have a one variable name and its initial value will be an empty string. You can also see a BY keyword which represents a property delegates indexing Kotlin. Basically, it will allow you to automatically unwrap them, mutable state the string into a regular string value. The type of our name variable is now a string. But if we replace this by keyword with the irregular equal symbol, then you will see that the type of our name variable a will become a mutable state of a string instead of a simple string. And I prefer using a bike keyword, so I don't have to type a name dot value anymore. Next, whichever member function, which will basically save the single object in our memory in a composition during initial composition, and the saved value will be returned during a recomposition. Also, we see a mutable state of function which is a wrapping our initial value. Now with that, our variable will be transformed into a state. And the state is observed by the Compose, which means that whenever we change that name, variable, composer will be notified and the part of our composable function will be updated because of the recomposition process. So we are able to update our UI only by controlling the state. And in this example, you can see that the only value change parameter of a text field will update the name variable whenever we type even a single character, which will then update the value parameter of the text field during decomposition. So we're now that you understand that you can only update your UI by changing the state, I want to introduce you with a stateful and stateless composable. So in the previous example, you have already seen that our composable function has a one state inside. And that's why our composable is actually a state for the opposite of a stateful, stateless, which would mean that our composable wouldn't hold any state inside. Now, stateful composable are hard to reuse and desk. So you should always try and keep all your composable stateless. Instead, to do that, you can use something called the state hoisting. And the state hoisting is a programming pattern where you move the state of a composable to the caller or that composable are simple way to do that is by replacing the state with the parameter and the using the Lambdas to represent events. Now let's transform our previous stateful composable into a stateless composable. So now you can see that there we no longer have a state inside our screen content. Instead we have a moving data state up in the composable higher heat to our color. So Lambdas are the most common way to describe events on a composable. In this example, you define an event called their own name change using the lambda that takes a string and thereby hoisting the state out of screen content, it's easier to reason about a composable, a reuse it in a different situation and test. So our screen content is decoupled from how it's state is stored. And the decoupling means that if you modify or replace the home screen, you don't have to change how screen content is implemented. So view models are the recommended state holder for a composable that are high up in the coupon is a UI tree or a composable so that our destinations in the navigation library now ViewModel so survive configuration changes. So they allow you to encapsulate the state and the events related to that, the UI without having to deal with the activity or a Fragment lifecycle that hosts your compose code. So your view models should expose the state in an observable hoarder such as the live data and the state flow. So you can have one or more observable state orders and each one of them should hold the state for the parts of your screen that are conceptually related and that the change together that way you preserve a single source of truth even if the state is used in a multiple composable. And in this example here you can see that we have moved the state all the way up to our view model. So ViewModel can be used to expose the state in an observable holder like a live data or flow, and also to handle events that affect that state. Here you can also see one new function which we are using it and that is observed as state. So our observed as a state of service, a LiveData object and it returns a state object that is updated whenever the LiveData changes and the state is an observable type that their jet decomposed can use directly. Now this example follow the unidirectional data flow pattern, whereas state flows down the home view model and the events flow up to the home screen. Now, this example followed the unidirectional data flow pattern, where a state flows down from home view model and events flow up from home screen. So basically this is how that example we will now work with the unidirectional data flow pattern. So we have an event on a value change is called in response to the user is typing a character, then, uh, we are updating the state, so On name change or function of a home view model, we'll handle the processing and then I will set in the state of the mutable LiveData underscore name and then we are displaying that state. So the value of a name, a variable from our home view model changes, which is observed by the composer in observe as state function. And then a home screen runs again or recomposes to describe the UI based on the annual value of a name. Also, there are tiny when you actually don't need to reuse a composable and you wish to have any internal state. Now let's take one custom composable as an example. Here we have a one expendable card as an example. So the expendable current contains the experiment internal state that defines whether the body should be shown or not. The beekeeping expanded as an internal state. Are you limited the flexibility of the composable? For example, you cannot set a default value of expended state or true in one composable usage and the false in another. And you cannot persist in their user's preference across the app recreation. So now you have seen a couple examples on how to use a states and events in a compose. You have also learned about the stateful and stateless composable us about the state hoisting and they're unidirectional data flow pattern as well. So for this video, that'll be all. 5. Compose Lifecycle: Hello there and welcome back. In this video, I'm going to talk more about the lifecycle of the composable and how compose their science or whether our composable needs a recomposition or not. As we mentioned in some of the previously dealers, we describe our UI by writing composable functions. And a composition is a tree hierarchy of the composable that describe our UI. Now, initial composition is when their gender composed around 0 combustibles for the first time and during that initial composition, jetpack compose a, we'll keep track or for all composable and that your call to describe your UI. And then when the state of your app changes jetpack composed, we'll schedule a recomposition, which is a basically a, a process or for recreating your UI by calling their same composable functions all over again with the new data. So our bottom line composition, it can only be produced by your initial composition and the updated by a recomposition. So the only way to modify our composition is through a recomposition. Now, a life-cycle of a composable in the composition is pretty simple. It enters the composition, gets a recompose the 0 or more times, and leaves the composition. So if a composable is called there multiple times, then are multiple instances are placed in the composition and they're, each core has its own lifecycle in the composition. Now, the instance of a composable in a composition is identified by each call site. So they're composed compiler considers each call site as a distinct. They're calling composable from our multiple calls sides will create a multiple instances of the composable in a composition. So a cool site is the source code location in which a composable is called and that this influences its place in a composition and therefore the UI tree. If during a recomposition, a composable calls different composable than it did during the previous composition. Then a composer we'll identify at which composable so work called or not called, and therefore the composable that to work called in both compositions, composer will avoid the recomposing them if their input haven't changed. Now in this code example here, a login screen, and we'll conditionally called the login arrow composable. And there will always call the login input composable. So each core has a unique call site and that source position and which are the compiler or will use to uniquely identify it. Now this is a representation of our login screen in their composition when the state changes and a recomposition occurs. So the same color on both sides means that composable. So heaven to recomposed, even though in this, uh, composed tree, a login input the went from being called the first two being called a second, the login input instance cell will be preserved across sorry, compositions. Additionally, because the login input doesn't have any parameters that have changed across the recomposition, the call to login input will be skipped and vital compose. So we're calling a composable multiple times. We'll add it to the composition and multiple times as well. And there when calling a composable and multiple times from the same call site, composer doesn't have any information to uniquely identify each quarter that composable. So the execution order is used in addition to the core site in order to keep the instances distinct. And this behavior is sometimes all that is needed. But in some cases it can cause unwanted behavior. And the here I'm using the example from the official Android documentation because I think it's already a well written so you could easily understand it in this example, composer uses the execution order in addition to the call site to keep the instance distinct in the composition. And the if a new movie is added to the bottom of the list, then a composers can reuse the instances already, the composition, since their location in the list haven't changed, and therefore, the movie input is the same for those instances. Now, this is a representation of a movie screen in the composition when a new element is added, the bottom of the list movie over your composable in the composition can be re-used. So the same color on both sides in the movie overview means that the composable so haven't been a recomposed. However, if the movies list that changes by either adding a new item to the top or the middle of the list, removing or reordering items, then it will cause a recomposition in all movie or view calls. Who's the input parameter has changed position in the list. And this is a representation of a movie screen in the composition when a new element that is added to the top of the list. So movie overview comparables cannot be reused and or side-effects will restart a different color in a movie overview here means that in a composable has been recomposed. So if we reorder the list of movies, we would also want to reorder the instances of a composition tree. Instead of very composing, get each movie or you composable with a different movie instance. So composed provides a way for you to tell the runtime what the values you want to use to identify a given part of the tree. And that is a key composable. So by wrapping a block of code with a call to the key composable with one or more values passed in. Those values will be combined to use to identify the instance in the composition. And the value for a key does not need to be a globally unique. It needs to be only unique amongst the invocations of composable at the call site. So in this example, each movie needs to have a key that is unique among the movies. And it's fine if it shares that key with some other composable. So elsewhere in the app, now, when using their key composable functions, whenever we add some new item and they're all items change its original position. For example, when we reorder the list, then a composer will still be able to recognize the individual calls to movie or ovule. And thus, we will be able to reuse all existing items that they haven't changed their instance without recomposing them. Okay. So that'll be all I wanted to share with you in this video about gender composer lifecycle. I hope that I have cleared the air about some of the things which you didn't know about the jetpack compose in general. So if you have any questions, feel free to send me a message and I'll gladly help you out. And for this video, that'll be all. 6. Side Effects: Hello there and welcome back. In this video, I'm going to introduce you with the concept of side effects in a jetpack compose and their first, let's start with the basics. So what is a side-effect? So a side effect is a change to the state of the app that happens outside of the scope of the composable function and all composable. So there should be a side effect free. However, when you need to mutate the state of your app from the composable, then you need to call that a side effect from a control. The environment is aware of their life cycle or the composable. And when you need to make changes to the state of your app, then you should use the effects, the API, so that those side effects are executed in a predictable manner. And effect is a composable function that doesn't emit a UI and their causes a side-effect to run when a composition completes. Now, let me give you one, a basic example of a side effect so you can see how it would look like. Now imagine that we have one composable function in which among other staff, we want to increase the number of one global variable. Now in this example here, we have a side-effect because we are trying to modify a variable and have our lives outside of the composable lifecycle. In that case, it can happen there too. We're receives some unexpected value in our number variable. And the why is that? Well, as you already know, a recomposition is a process which is controlled by a jetpack composer framework directly. And we don't have that much control over that process, which is totally fine. So in our example code here, our composable function might the recompose them multiple times, even in multiple times in a second. And whenever that happen, our number variable a will be increased by one every time. So now you can see why is that the actually a bad thing. Instead, what we should do, we should call one of those are functions from effects API and the inside each sunblock we need to put all our side effect codes. Now this was just the one in simple, basic example. But just imagine what will happen when instead of this incrementation line of code, you add a function which main purpose is to request a data from an API. Now place net side-effects and directly incentive composable function. And imagine what will happen with that function if you already know that we don't have a control over a recomposition process. Well, the most likely outcome would be an app crash because you would soon out of our resources. So it's really important to properly handle euro side effects and therefore cases when their side effects are necessary, composer has a bunch of methods to execute them in a controlled environment. And those functions are called the effect, the handlers, that way we can control the life cycle of these side effects. So they do not live longer than a required and there are cleaned up once they're no longer needed. Now we can import the effect, the handlers in two different categories, non suspended and the suspended and effects and a non suspended the effect the handlers or run a side effect to initialize a call back when the composable enters the composition and the dispose it when it leaves, they're suspended effects. I can load data from the network to feed some UI state, for example, now in the first and non suspended the effect, the handlers say category, we have our functions like a side effect and these plausible effect, for example, there are a few more of them, but those were some of the important ones. And in their second they're suspended effect a handlers group and we have a functions like allows the effect. Remember coroutine scope and so on. And I'm not going to talk in more details about each one of those effect the handlers functions. However, you can check the official Android documentation and read about them in more details. Nevertheless, one of the most used effect, the handler is launched effect, that this effect accepts two parameters. The first one is a key and the second one is a coroutine scope block. So allowance the fact that we launch a coroutine tied to a scope of the composable and they went to launch the fact that enters the composition, it launches a coroutine with the block of code passed as a parameter. So the coroutine will be canceled if a large defect the leaves the composition and also launched effect is quite useful because you can also pass the key instead its parameters. For example, you can pass a state as a key or phalange the effect and the debt would mean that the largest effect that will execute the block you pass to it every time the key changes and the after the key changes, then the existing a coroutine will be canceled in the new suspend function, r will be launched in a new coroutine. So well, that'll be all for this short video about the side effects and the effect the handlers. So be sure to check the official documentation for more information about each and every effect the handler or functions ending the future videos of these scores or you will see in action some of those effect handlers for this video, and that'll be all. 7. Layouts: Hello there and welcome back. In this video, I'm going to introduce you with layouts in a jetpack compose. Now in the traditional view system, we have declared that all our views along with the layouts in XML. So there was a little problem with that approach. Whenever you create a nested layouts, then the performance of your application water slightly drop. Now in a letter composers that everything is done in a Kotlin file and we don't have that issue anymore, so we can nest the layouts without a problem. High-performance energetic compose is achieved by a forbidden measuring layout children more than once. So there are three main layout composable, which you can use in your project to create almost each and every design out there. So we have a column, a row in a box. Also, we can create a custom layout as well. But for now I'm going to just focus on those three main or layouts. First, let's start with a column. So column allows you to align all its children in a vertical orientation. Savoir column assets are multiple parameters. The first one is a modifier and the second one is a vertical arrangement. The third one is a horizontal alignment, and the fourth one is the content composable lambda in which we place all its children. Now the first parameter modifier is one of the most popular energetic compose because it's present on each and every composable function out there. And they're modifier allows you to add them many different decorations and apply a certain behavior to your composable. You can use it to set the size of the composable, for example. And there when used with the layout composable most over time, you will use a modifiers like feel max size, feel max height. Next up with and that padding for example. There are also many more so you would hear to experiment with it by yourself, glass. So when we start building our application, you will see all of that in action. Now the next perimeter is a vertical arrangement and it's used to specify the arrangement of the layouts children in a vertical axis. So with a vertical arrangement that we are moving our elements and vertically because we are talking about the column. And if you're using a row instead, then there should be a different parameter named the horizontal arrangement, because a row is going to display all its children in a horizontal orientation on a horizontal axis. Now let me show you a few examples of using a vertical arrangement with the column that those examples could also be applied to a row as well, but with only one difference, and that is an orientation. Now let's say we have a column and therefore different elements inside the column is taking a full screen size by specifying a modifier named the field max size. Now default vertical arrangement of ALU is top, which means that all elements will be located on the top of the screen. So while we can set the vertical arrangements to be on the center or on the bottom of the screen as well. And that way, all of those elements inside that column a will also be moved either on the center or at the bottom of the screen. Now there are three more interesting options available for the vertical arrangement. We have our spacing between space around and the space evenly. And then now let me show you how those are elements in set a column or will be arranged when they're using each one of those three options. So if we specify a space between option, then our elements inside that column, I will take all available space. And the between each one of those elements, we will have a blank space as well. Next, if we specify a space around, and that would mean that our elements will take a full screen. Now once again, there will be a space between our elements plus a blank space will be added at the beginning and at the end of the column to the space. I will not take the same amount of space between elements and around them. And the finally, the last one is a space evenly. In that case, we will hit a blank space so evenly placed between elements and around them as well. And the third parameter inside our column is alignment, and that is a horizontal alignment. On the other hand, when using a row, then you will have a vertical alignment instead. Now all it's a set, both the width and height to our elements inside that column to be, for example, 100 UNDP. And our colon will still take the full screen sizes before. So now you can see that a default value for a horizontal alignment is the left side or right side. Also, we can change that to either a center or end. And this is how it would actually look like. Now all those are three main parameters which we have mentioned. The hero on our column can be applied on the row composable as well with the just the one more change and that is an orientation. Now a column layout composable is a lot similar to the linear layout with a vertical orientation from the view system. And the row is similar to the linear layout with a horizontal orientation. So now that you have been introduced with the most important the layout composable. Let me show you the third one, which is a box. So a box can be compared to the frame layout which we have inside our traditional view system. And they're each new element that we put inside our box will be placed on the top of the other. Also, one last important thing to remember is when using a modifier. So modifiers are applied and the executed in a specific order from first to last. And that sometimes can happen that, for example, let's say you are adding two modifiers, our background color and the padding. Now if you add the padding first and then a background, then the padding which we have specified will not be colored in the same color as the background. Instead, it will not yellow color. But if you instead the ad, the background modifier first and then the padding only then the pending here we'll hear the same color as the background that you have specified. So why you need to keep an eye while adding multiple modifiers? Because, uh, you might not get the things you expect it to our right. So now that will be all for this video. You have alone. There are some of the most important things about the layout composable and how they work. And then in the later videos of this course, of course. So you will see in action how all those layout composable functions are used. Sulfurous video, that'll be all. 8. Create the New Project: Hello there and welcome back to when your videos. So in this video, we're going to create a new Android Studio project from scratch. And I'm going to show you all the files which will be automatically generated by our new template name, the compose activity. So now let's create here a new project. So file then a new and let's create a new project. So here we are not going to select the empty activity anymore. Instead, we're going to choose the empty composed activity template because this template that will generate all the necessary files we need to actually create our application in our gel decompose. Now let's click Next, and I'm going to name this project to do compose. All right, so here the minimum SDK will be 21 and click finish our iron solid. Just wait a few seconds until Gradle finishes its progress. So here you can see that the in our project we have our main activity. And also here we have our UI package. And inside the UI package we have a theme baggage. And that theme package contains four different Kotlin files. So I'm going to show you each one of those files about for now. I'm going to just remove those two functions from our MainActivity because we are not going to need them at this point. This suggests the summer auto-generated code. We'll just remove that are right in here also, we can remove everything as well. We can just leave this to decompose a theme composable function, which is actually located in our theme Kotlin file, which I'm going to show you right now. So the first thing you can see here, you can see that inside our own creative function, we have a set content composable function. And if we click on that and now press Control B, then we can open up the source code of that set content composable function. And you can see that this setContentView function is an extension function on a component activity and it composes they're given a composable into the given activity. So the content of this composable function will become the root view of the given activity, our case. So we can just close that for now. And basically inside this a composable function, we have our to-do compose a theme function. And inside that composable function, we're going to basically add the, all our composer tree hierarchy, which are you're going to see in the future videos. For now, let's just leave that as it is. And the less checkout all other costs in files which were automatically generated by this composer activity template. So first let's open up the color Kotlin file. And here you can see that there are four different colors which were defined. So we have our purple over two hundred, five hundred and seven hundred, and also this teal to a 100. So here you can see that each one of those variables are using this color function. So if just select that color and press Control B, then we can open up the source code of that function. And if you read the comment from above, then you can see that this function, we basically create a new color instance from a RGB color integer value. So basically this is the new 32-bit, a RGB color integer value, which we need to specify to this color function by using this specific format, like here and there for now I'm going to leave those colors, but in the future we are going to add a few more colors in these Kotlin file and all your new colors for this project that can be defined the right here. And now let's open up a new file named the shape. So here we have only one variable named the shapes. And inside that variable we are calling these shapes class. And basically these shapes class is used to define three different shapes like a small, medium and large. And here we have defined the rounded corners shaping this case. So the first to have ADP off for a while, this largest one have a 0. And of course we can change those values, but I'm going to leave that as it is for now. And next time I'm going to open up this type Kotlin file. And here we are defining our typography. So we have only one variable named the topography. And that variable is basically calling this typography class. And that topography class contains many different parameters or different text styles like a 123456, then a subtitle 12, body 1 and 2, then a button caption and overline. So you can check out this whole class if you want. Those are some just default text styles, which we can see hearing these topography class. So from our causing file here, we can of course, override the other default text styles. And we can change. Of course, there are font size, font weight, and even a font family. Now, I'm not going to need the L because I am going to use a default typography about later in this course or at the end of this course, we might just add a new font family and change our typography so you can actually see how will that look like. But for now I'm going to leave that as it is. And finally, let's check out our theme Kotlin file, which is basically one of the most important Kotlin files in our project here. And first thing you can see here we have our two variables, dark and the light color palette. And each one of those variables are using different functions like a dark colors and light colors. So basically each one of those functions contain many different. Material color, specifications. So here we have a primary, primary variant or secondary, secondary vary and beg round surface error. Primary on primary and secondary on background on surface and onError. And of course from our team or Kotlin file, we can change those values. So by default that we have only changed that those three values. So primary, primary variant, and a secondary. And as you can see, those colors are grabbed from our color coding file, which is again, automatically generated file as well. And down below, if we press Control P, we can see or other parameters which we can change. So for example, we can type here are beg round and we can change the background color as well. Our case, we can just type here some new color to change the background. And we can do the same in our dark color palette. For now, I'm not going to modify anything from here on. Then let's scroll down below. And here you will see our to-do compose a theme function which is called the from our MainActivity. So this to-do composer theme function accepts two parameters from which the first one has a default argument and it's a Boolean value. So here we are basically calling this function name that is a system in dark theme. And this function will return true if our Android device is using a dark theme and it will return false if he doesn't. So if these dark theme is actually true, then we're going to use a dark color palette in our project. And in this case we're going to use a light color palette. So this code there right here is very convenient for us because later in this course, it will be a lot easier for us to actually customize both of those themes like a dark and light theme. And you will see about that later on. And the inset is to do composer team. We are calling our Material Theme composable function, and that's basically the roof of our composer hierarchy. So basically to this function, we are passing our caller's variable. So if a dark theme is true, then we're going to pass a darker color palette. And the if we are using a light theme in our Android smartphone, then we're going to choose a light color palette, then incidence, Material, Theme, composable function. We are passing our typography and the shapes, and you have already seen those two files in the final perimeter here is that content Lambda. So this is a content lambda means that we can, they're fine. Our composable tree in our MainActivity and all that content will be inside that material theme. Okay, So we can of course open up this material theme composable function by pressing Control B so you can check out and see the source code of this function now. Okay, I'm going to close that for now, but you can read that as well. And basically, whatever we define the inset, our MainActivity here, our to-do compose a theme. We'll basically represent the rules of our composable hierarchy. So now you should have been successfully introduced with basic I compose activity template, android Studio on whichever checked all the files which were automatically generated by this template. We can have, of course, the open-up by Gradle build files to see what do we have here for now, our case. So here you can see that at this point we are using a composer version 1. This is the first stable version at this point, and as I already mentioned in some of the previous video, this course, so we'll be constantly updated so you don't have to worry about that. Next, let's open up a Gradle build file module application. And here you can see that the minimum SDK is 21, target SDK is 34 now. And then below we can see some are more dependencies which were automatically added right here. So you can see that we have a bill feature compose That's all are automatically added by this compose activity template. And here I can see that we can change this composer version to 1.1. So let just update that from here. So 0.1, Let's now sing that now. Okay, perfect. And in the next video I'm going to also add some more dependencies which we are going to need for this application. And for this video, that'll be all. 9. Add Dependencies: Hello there and welcome back. So why in the previous video, we created our Android Studio project. So y in this video, now is the time to actually add the summer dependencies, which we are going to need to actually create our application. So let's open up both of those Gradle build files and they're here down below. I'm going to just paste some dependencies. So here for now we have a room, a datastore, and the dagger Hill dependencies only now or that might change in the future. So we might add some new dependencies. If we are going to need for now we need the only those three. Okay, so let me scroll up here and I'm going to add also to more plug-ins. So Kaupthing kept and that bigger hill to Android plugin. And in the second Gradle build files and we're going to add here only one that class path for my yard. They are Hills Library. And now we can just sync our project to see if everything is going to work fine, our case, so we haven't received any error, and now we can even run our application to see if everything will compiler correctly. Okay, so now I have received their one error and I went to run this command from here. So let me just copy that and we're going to check out and see what is actually causing this error. So now let me open up the terminal. And here I'm going to write Gradle w space, and I'm going to paste that code. And also I'm going to add here a stack trace. I'm going to press Enter r k. So let me just see what this error is all about. So here it says caused by this evil issue exception. So Android Gradle plugin requires a Java 11 to run. And there we are currently using 1.8. Okay, so to fix that, I'm going to open up the settings. So file, then our settings and the hero. I'm going to open up our build execution and deployment. Here let's search for Gradle our k. And here I need to change this from a 1.8 to 11, our case for now, let's apply that and let's click Okay, and now let me just run this app per once again. Okay, so now I have found out that this current 1.1 version of the compiler requires that cotton version of 1.5.21. So here I'm going to just change that to 21. Well, just seeing the project, let me run the app again, Okay, and now our application has been compiled and run successfully. So we're at a demo for recording this video. I'm using this clotting Gradle plugin 1.5.21. Of course, there is a higher probability chance that you are not going to get this error at all. Anyhow, I have just shown you how you can just debug and see what this is all about. And then now we have added the all necessary dependencies which we are going to need for this application and for this video, that'll be all. 10. Create Model Classes: Hello there and welcome back. So why in this video, we are going to create the tool model classes from which the first one will represent an entity or a table in our database. And the other one will be a priority E&M class, which will be used as a field in our entity class. So the first thing we're going to create here a new package. So let's add a new package name that data. And inside that data package, I'm going to create a new package called them models. And inside that new package, I'm going to create first one, a data class named to do a task. And this class will be actually a data class. So now I'm going to annotate this class with the entity annotation. And this is a notation from our rule, my library. So with this annotation, we are telling our room database that this data class will be used to actually create a table in our database. And now we're going to specify all fields inside this to-do task. And each one of those fields will represent our column instead our database table. So before I continue here, I just want to create a new model class here, which will present a priority. So let's create here a new class, our key priority. And let's choose a down below E&M class. So inside this E&M class, I'm going to just add the one parameter and that is the color of a type of eye color. So android.jar graphics are k Perfect and our enum class so will contain our four different values. So first I'm going to add the high, so high priority, then a medium priority, a low priority. And finally I'm going to add a non. So we're going to need this later in this course. And you will see, so now as you can see inside there, each one of those enum entries will need to specify a color. So I'm going to now open up our theme, and I'm going to open up a color Kotlin file, our k. So here I'm going to paste some more colors. So our low priority, a medium priority, high priority and non priority color. So a low priority, we'll basically have a green color. Medium will have orange, high will have a red, and these are non, we'll have just a simple white color, our case. So now we can close that and we can pass those colors are right here. So high priority color. Okay, so we need to add the different import right here. So Android X.com dot dot Graphics dot color. Let just import this one more time, our case. So this one here, I'm going to pass a medium priority color down below. I'm going to pass a low priority color in here. I'm going to pass a non priority color. Okay, So that's how our priority enum class will look like. And now this priority in and class will be inserted in our To-Do Tasks entity, our case. So now let's go back to our to-do task. So now before we add some fields into our to-do task, a t here inside our entity annotation, we need to specify a one parameter and that is our table name. So I'm not going to hard code this table name a string right here. Instead, I'm going to create here a new package. So let's create here a new package name that you feel. And inside that package will need to create a new Kotlin object named the constants. And here inside I'm going to add the first constant. So const char, Val. And I'm going to name this constant database table. And the here I'm going to write the todo table also down below, I'm going to create one more constant which will be named that database name. So the name of our database and that name should say to-do database. Okay, we're going to need that for later or for another video. Never mind. Let's go back to our to-do task. And here we're going to pass that constant. So database table, we'll just import that allright perfect. And now inside our to-do task entity, we are going to add four different fields. And each one of those fields will represent our column inside our database table. So the first one will be the ID of a type of integer, and we're going to set its default value to 0. So this ID field will basically be automatically generated by our room library. And in order to tell our room library to auto-generate that number, we're going to annotate this field with a primary key. And here we need to specify auto-generate to true. Okay, so now this field or this value will be automatically generated by our rule, my library. And whenever we create a new to-do task object, we are not going to need to actually specify that the first ID, instead that value will be automatically handled by our own database, our case. So the next field or column inside our database table should be name, the title, and the type of that to be a string. Then a down below the third one will be description of a type of string as well. And the final one will be priority. So the priority in AM class, which we have already made before, alright, perfect. So now we have successfully created our entity class, which will basically represent a database table in our database. We have also created the customer enum class, which will represent different priority for our tasks. So we have our four different priorities, high, medium, low, and non. And for now we're going to just leave that as it is. Also we have greater than your constants causing object in which we're going to put all our constants. And if you recall, we also have added the four different colors in our colors. So Kotlin files, so there really is so well for this video, that will be all now we have successfully created our entity and our priority model class. So why in the next video, we're going to probably create or a setup our own database. 11. Introducing with ROOM Database: Hello there and welcome back. In this video, I'm going to introduce you with their room library for Android. Now, Room library is one of very useful library for Android developers because it provides an abstraction layer over SQLite to allow us to work with the local database seamlessly. Now for those of you who are not familiar with this library, you might be asking your, why would we need a local database anyway? Well, the answer is pretty simple. In most cases, local database is used when saving data in a view model is not enough and you need a way to persist the data so you can access it again when your app is destroyed or when you launch your application once again. Now, there are three main components in a room library. The first one is a database class that holds the database and the acts as the main access point for your SQL queries, which you write in your Tao, which is a short for a data access object. Then at the second main component is a DAO or a data access object, which provides the functions that your application can use to query, update, insert, and delete they think the database and the third and final component in our room library is entity. And the entity represents a table in your database. So of course you can have a multiple entities or a multiple tables in your database as well. And of course, you can create a multiple data access objects for a multiple tables or entities as well. So this is one basic example of how we can define a table structure in your database by annotating your a data class with the entity annotation. So are inside the constructor of a data class, you can define the fields and each field will represent our column in your database table. Now, each entity you create should have a primary key. You can tell you a room library which field there should be a primary key just by adding a primary key annotation plus a, you can specify auto-generate parameter to true, which will mean that the room library itself will handle incrementation of that integer value by itself. So you don't have to worry about that. Next, instead of this data class, you can also see that we have defined the two string fields, first and last name. So the name of the column in your database table will be the same as the name of those variables you have defined unless you add the column info annotation to specify a different name for your column. Next, here we have just one simple example of a dao interface. Now, there are some a predefined annotations in a room library which I can handle SQL queries by themselves, like insert, update, and delete. So we can also define our own custom SQL queries by using this query annotation like you can see here in this first I read all function. And you can also see that on the insert query we have a specified something that's called the conflict strategy. It basically means that you can specify what you want to do if a conflict happens in your database table. So there are three different conflict strategies which you can choose from. The first one is a replace, so it will basically replace the old data and continue with the transaction. Then we have a board on corporate strategy, which basically means that the transaction will roll back. And the third one is Ignore on complex strategy, which will just ignore their conflict. Then finally, this is how you can define, for example, you're a database class. So a database class must satisfy the following conditions. First one, the class and must be annotated with a database annotation that includes an entities array, or the least of all entities connected with your database. Then our second your class and must be an abstract class that extends from a Room database. And the third, for each DAO class that is associated with the database, the database class so must define an abstract method that has a 0 arguments and returns an instance of that now class. Now, using a Room database in your project, you should follow a singleton design pattern when initializing your database object, because each room database instance is quite expensive and the URL we need an access to a multiple instances within a single process. So to achieve that, that we will be using a dagger hilt. The library to provide a database instance is a singleton component in our application. So now you have been introduced with the Room database in general. And from the next video we're going to start setting up our own database in our project. So for this video, that'll be all. 12. Setup ROOM Database: Hello there and welcome back. So in the previous video, we have a created to model classes from which the first one I represents an entity or a table in our database. So you can see that our two tasks Chordata class, so we'll have four different fields, and each one of those fields will represent our column inside our database table. So while one of those fields is a priority E&M class, which we have already made in the previous video. And each one of those priorities contain a different color. We're now in this video, it is time for us to actually set up our room database. And that to do that, we are going to create a dao interface and the Room database class. So first, let's create a dao interface. So inside our data package, Let's create here a new Kotlin class or interface. And let's name this interface to do now. Okay, so we need to annotate this interface with the Dao annotation. And for those of you who are not familiar with a Room database at all, dow is a short for a data access object and inside our Dao interface. So we will need to define our, all, our SQL queries, which we are going to use the width our database table. So it's a good practice to create a multiple Dao interfaces for basically each and every database table you have in your database. But for our application we are going to have just one database tables. So that's why we are creating just the one dow interface. So now inside this dao interface, I'm going to declare a multiple SQL queries, which are, I'm going to need the width my application. So first, let's start with the first one. So I'm going to name this function, get them all tasks. So this function will basically read the old tasks from my database table and that this function should return a flow. So a Katlyn coroutines flow. So we should wrap a list of two tasks in a flow. So because we're getting all the tasks from our database, we want to wrap this to task class in a waste because we want to return a multiple To-Do Tasks. And of course here we're using a flow which is basically in an asynchronous data stream. And the here I'm going to annotate this function with the query annotation. So there are multiple annotations which we can use from our room database like insert, update, or delete for example. But in this case I'm going to use one annotation name their query. And this annotation will allow us to basically specify our own custom query inside the parameters of this annotation. And the hero, I'm going to write an SQL query which will basically read all the tasks from my database table. So if you're not familiar with the SQL queries, then I highly suggest you to check out this website, which is called the W3 schools.com. And here you can find them many useful tutorials about using the SQL. So here I'm going to write a custom query. I'm going to write select that. I'm going to add this star which is basically representing all. So select all from. And I'm going to type here the name of my database tables. So todo table, as you can see, as soon as I type tool, I'm going to get this name of my table. So select the everything from todo table. And I'm going to just Order or a sort this list by ID, which is an integer primary key. And I'm going to store that in an ascending order. So basically I'm selecting everything from my database table. So todo table and I'm sorting those results by ascending order. And the result of this query will be our list of two tasks wrapped in a flow data stream. So down below I'm going to create one more function, but this time we are going to get a single task from our database table. So let's name this function. I get selected task and again, I'm going to return a flow, but this time I'm not going to use the list. I'm going to just pass a total task because I'm going to return a single to-do task. So now I'm going to also add here a query annotation, and I'm going to add here a custom query again. So here I'm going to write a Select All again from my table to do table where. And now I'm going to type the ID. So we're ID is equal, where ID is equal to task ID. And we're going to receive this task ID from the parameters of this function. So let's add here a task id of type integer. So this is the actual format in which we can pass this perimeter into this query. So first we need to type the column name, which is ID in this case, then r equals symbol. After that we type of column and then the exact name of our parameter. So later from our code, when we want to request just a single task from our database with the specified ID, then we can just pass that the ID through this function. And then that the same ID will be used to locate our specific to task which we are searching for. All right, so next let's create another function. So this time I'm going to create a function for inserting or adding a new task to our database. So I'm going to name this function, Add a task, and as a parameter I'm going to add a to-do task. That this function or will not return anything. Plus we're going to add the new annotation here called the insert. And the sanitation is a part of a room library. So just edit here. And also I'm going to add here a suspend keyword because this function will be run inside a coroutine and that's why we need to either suspend keyword. So now you might be wondering, well, why didn't we add this same suspend keyword in those first two functions? And the reason is very simple because those two functions are using flow, which is actually a part of coroutines library. And this flow is actually running asynchronously by their fault. That's why we don't need to add this suspend keyword right here. But all other functions which we don't use this flow should have this suspend keyword included. So that's all we need to write inside this function to actually add our To-Do Tasks in our database. And also there is one more thing. So here we need to specify one parameter and that is on conflict as strategy. So here we need to specify on conflict strategy and there are many different options to choose from here so we can replace our board fail ignore the rollback. So for example, let's choose this ignore and let's press Control Q here, so we can read more about that. So here it says an insert and dow method that returns the inserted, the role IDs will return minus1 for rows that are not inserted, it seems this strategy will ignore the row if there is a conflict. So if there is a conflict in a to-do task ID, then we can select their own conflict strategy to be ignore. So we can just ignore that or we can add, for example, a replace. So we can just replace the old one with the new one. And in this case, I'm going to just add this, ignore a conflict strategy, but of course you can use some different strategy if you want. Next, let's create another function which will represent an SQL query. So now I'm going to create another suspend the function name the update task. And here we're going to pass to task which needs to be updated. And we're going to add here annotation named the update. So that's all we need to do to actually update our two task from our database table. Next I'm going to add here another suspend the function name, the delete tasks so we can actually delete one of those tasks from our database table here. We also want to pass this to-do task as a parameter of this function. And let's annotate this function with the update or sorry, and Delete annotation, which is as well part of our room database library. Our next we went well another function, but this time for deleting all tasks from our room database and not just one. So let's create here another suspend function name that the elite or a tasks. And here we don't want to pass or anything. We just want to annotate our function with the query annotation because we want to pass here our custom SQL query. So here I'm going to just write delete from and I'm going to write the name of our table. So this SQL query will basically remove everything from our database table. And next, I'm going to create a new function for us searching our database table. So this time I'm not going to suspend keyword. I'm going to just use a simple function, name the search, our database in here as a parameter, I'm going to add a search query of a type string and this function should return a flow, so called an x coroutines flow. And here we want to just pass our list of two tasks. So whenever we search our database and we want to pass a search query into this function. And we want to return a list of a multiple tasks wrapped in a flow. So now let's add here a custom query again. So here in our database table, we want to be able to search for both the title and description to actually find our glue tasks. So here I'm going to write a select all from then a todo table where title, so the title is the actual column in our database. So let's select that. So we're our title. Then I'm going to use this Solexa keyword from our SQL in here. I'm going to pass that search query from the parameters of this function. So basically, we want to select all tasks from our database table, where a title contains some string which we are going to pass from the parameters of this function through this search query string. And then we're going to type or we're description also is like this same search query. That's how we are able to search both title and description with that same search query which we specify in this function. And of course, if you're not familiar with the SQL queries, again, you can just visit that website, which I have shown you earlier to learn more about that anyway, there are two more functions which I need to add here. And those two functions will be used to actually sort our results or our tasks by priority. Okay, So now let me just create here the first function which will be named the sort by low priority. This function will not have any parameter and it will return a flow of our list of to-do tasks. Let's add here a customer. Again, so this query will be a little bit longer, but don't worry, I'm going to explain later on. So let's again select all from our to-do table and we want to sort the result. So orderBy, now, the first case when the priority column is a similar or like, and now I'm going to add single quotes here. And I'm going to type the first character, which is a capital letter L. And I'm going to add here this symbol. So this L means that we want to sort first those tasks. Let's start with L, which is a law, which is a low priority. Then I'm going to write here one. So next, when priority is like M, which stands for medium. So let's add here this symbol as well. Now, I need to also type here then number two, when priority, like age, which is connected with our high priority. And let's set here that symbol as well. And here I want to add then three. And so now let me just read this SQL query again. So basically here we are selecting our whole database and we are sorting the results from our database table and buy a priority. So first we want to get all the priorities were priority column contains this L character, which is actually our low. Then after that we are selecting or sorting or priorities which contains m, which is a medium priority. Then finally, we are putting all other tasks at the end. So the tasks who contain a priority, which contains this character age, which is connected with our high priority, of course. And that's how we are able to basically sort all our tasks by priority column. First that we're getting all those tasks that contain the low priority. Then after that we are adding all tasks with a medium priority. Then we are adding those tasks which contain a high priority. And that's how we are able to sort all our tasks via this priority, our column. And finally, I'm going to just copy this one more time down below. And I'm going to rename this function to sort by a high priority in our k. And here I'm going to just change this to age. So for us, we want to get all high-priority tasks that are medium ones and finally, our low tasks. So that's how our to-do Dao interface will look like. In now we have, they're fine. They're all SQL queries which are we are going to need in this project. And the last thing that we need to do here before we end this video, we need to create a new class. This class will be named the to-do database, and this will be actually an abstract class. So now we need to NO2 this class with a database annotation. So this one, and here we need to specify multiple parameters. So the first one is entities in here, when to specify all our entities or all our tables which we have in our database. And in this case we only have a one or entity or a one table, and that is to do a task. Entity are came. The second parameter is the version of our database, which is just a one because we can just created this database in the dirt perimeter will be an export schema. And here I don't want to generate these experts schema, so I'm going to set that to false also our class so should extend from a Room database and hearing side, we're going to just add the one abstract function called the to-do dow ended this function should return Lu Dao interface, and that's all we need to add inside our to-do database class. So for this video are that will be all. So now we have successfully created the, all our SQL queries or a functions which are we are going to use in our project later. And we have also created our database class. So now you might be thinking, Where should we actually create our own database builder and the debt, their own database builder will be created in our bigger hill term module, which we are going to create in the next video when we actually set up our dependency injection. So for this video, that'll be all. 13. Introducing with Dependency Injection: Hello there and welcome back. In this video, I'm going to introduce here with the concept of dependency injection. So why dependency injection is a popular technique used in the programming in Android development as well. By following the principles of dependency injection, you lay the stronger groundwork for a good application architecture and that there are three main benefits of using dependency injection in your project. The first one is reusability of code, and the second one is the ease of refactoring, and the third one is the ease of testing. Now, let's start with the basics. So what is dependency injection anyway? Well, uh, you know how classes often need a reference to other classes. For example, a class named computer or might need a reference to other class, such as a processor, for example. Now this processor class is called dependency and its dependencies for our computer class, because a computer depends on our heavy instance of our processor class. Now there are three ways for a class to get an object it needs. The first one, the class can construct a dependency needs in our example, computer would create in the initialize its own incidence or the processor, the second one class, so would the grab it from us somewhere else? For example, summer enjoy the APIs such as a context or I get system service work this way as well. And the third way is to pass it as a parameter. So the application can provide these dependencies when the class is constructed or a pest damage the functions that are needed. Each dependency in our example, the computer class constructor would receive processor as a parameter in this set. Third way is actually a dependency injection. So with this approach, you would take the dependencies of a class and provide them, rather having the class instance obtain them itself. So let me show you that example without the dependency injection. This is not an example of dependency injection because the computer class is constructing its own processor class. And that these can be problematic because there are two main reasons. The first one, computer on one side and processor on the other are tightly coupled, which means that an instance of a computer class uses one type of a processor and no other subclasses or alternative implementations can easily be used. So if a computer word to construct its own processor, you would have to create the two types of old computer instead of just reusing the same computer instance for different type of processor. And the secondary reason is because the heart dependency on processor makes testing more difficult. Now, let me show you our class. So would look like with other penance injection. So instead of constructing its own processor object, we can pass it as a parameter in its constructor. And then now we can also create them multiple subclasses of our processor class. So for example, we can create Intel and AMD is some classes for this example. And then now we are allowed to choose that which a subclass we want to pass slower computer class when initializing it. So now we don't need to create two different computer classes. Now we can just initialize one of the subclasses for our processor, and we can pass that their processor directly to our computer constructor savoir. In the previous example, we have created the provided and manage the dependencies, different classes and by ourselves without relying on a library. And this is called the manual dependency injection. In their computer example, there was only one dependency, but more dependencies in the more classes can make a manual injection or dependencies and more periods. Also, manual dependency injection presents a several problems for a bigger apps. For example, taking all dependencies and connecting them correctly can require a large amount of our boilerplate code and in a multi-layered architecture, in order to create an object for a top layer, you have to provide all the dependencies of the layers below it. And a second, when you are not able to construct and dependencies before passing them in, for example, when using a lazy initialization, you need to write and maintain a custom container that will manage the lifetime of your dependencies in memory. Now, there is a solution for that and that, that is a library called the beggar hilt, which is a recommended library for dependency injection in Android development. And I'm going to talk about that library in the next video. For this video, that'll be all. 14. Setup Dagger-Hilt: Hello there and welcome back. In this video, we are going to set up our dagger shelter library and get everything ready so we can easily use dependency injection in our project. Now the first thing which we need to do is create a new class which will inherit from application class and the annotate data class with the hilt, the Android app annotation. So we're inside, our rules are packaged. Let's create here a new Kotlin class named the to do application. And this class should inherit from an application class. So this one, r, k, and we also need to annotate this class with hilt android app annotation. So this annotation will trigger a Hilts code generation, including a base class for our application that will serve as the application level dependency container. So what this generated healed component is attached to the application objects are lifecycle and it will provide dependency to it. So after that, we can just go to our AndroidManifest file and we need to add a name attribute to our application tag. So let's add here a name and we need to specify here our application class. So this one, our case. So now we can close that and also we can close this application class as well. So next, we also need to annotate our MainActivity with Android entry point annotation. And the main reason for that is so that the hilt can provide dependencies to Data android class that he has enjoyed Andrey point annotation. So let's open up our main activity. And here we're going to add the enjoyed the entry point annotation or came. So since we are using a jetpack compose the UI toolkit, we will only have a single activity, 0 fragments and the multiple comparables. That way we only need to annotate our main activity with this Android entry point annotation. So after all of that that we need to create here a new package inside our project. I'm going to name this packager the eye, which is a short for a dependence injection. And inside that new package, I'm going to create a new Kotlin object, which will represent hilt module. And I'm going to name this object database our module, our K brands center. So in this module, we need to describe how we want to provide instances of a certain types which we want to inject later. Also, one more important thing to note is that sometimes there are situations when we cannot construct or inject a certain type. For example, we cannot construct our inject and interface, and we cannot construct or inject the types that we don't own. In our case, we don't own a room libraries, so we need to create a module. And here we need to describe how to provide any instance of a Room database to our application. So we're in the documentation of the agar Hills Library. They say that you cannot construct a inject and interface. And that's why we are going to inject our Dao interface, which provides annotation from our hilt module. But in order to inject our Dow first, we need to describe how to provide a Room database builder. So the first thing which we need to do here inside our database module or our hilt module, I will need to annotate this object with the module annotation. And after that, we also need to add one more notation called the install in, in here as a parameter, we need to pass in what components do we want to actually use this module? And since here we're going to describe how to provide the room database builder and willing to hear yours a single donor component. So this one, so now inside this a database, some module I'm going to create a new function called The provide a database. And I'm going to annotate this function with a single toner annotation and also it provides a notation. So this a singleton annotation means that we're going to have only one instance of our room database builder show will be used across our application. And this is actually a good thing because I having a multiple instances of a Room database can be expensive for our application performance and provide the annotation will basically describe how to provide the instance of our database. So here as a return type, but we're going to have our room database builders. So let's type here a room. So AndroidX daughter room than a database builder. And if I press Control P in CDS database, so Builder, we can see that the first parameter here is the context. So how can we pass the context from this module? Well, are very easily, uh, so in the perimeter, so this provide database function, we're going to other contexts as a parameter, but also we need to annotate this context with the application contexts notation. And this notation is also a part of a dagger healed the library, which will provide us with the context. So now hearing in our database builder, we can pass this context. So we'll just rename this to context instead of that content are k. Now it's passed here that first parameter, then the second parameter is the actual database class. And in our case that's a to-do database. So class dot Java are K and the final parameter here is the name of our database. So if you recall, I have already created the one constant for the name of our database, which is a to-do database. Okay, just passed here a database name. And let's import data constant, perfect. And finally, I'm going to call here build function so we can provide our database. Now, that's how we have described here in our module how to provide the instance of our room database, the after-death, we need to add one more function to provide our Dao interface. So also we need to annotate this function with two annotations singleton n provides. And here as a parameter of this DAO, we need to add the database. So a to-do database. And that's why I first created this function so that we can later a pest that instance to our second function. And here we just want to return a database dot to do doll our case. So that's all we need to write here inside our database module. Here now we should describe the how to provide our room database and our DAO as well. Now in the next video, we're going to create the repository Insight Data Repository. We're going to inject our Dao interface and not our database. But of course, as you can see, in order to provide our DAO, we needed to create a Room database builder because we needed to specify the name of our database and to actually build our own database. So basically that's all we need to do to actually set up our dagger Hilton library in our project. And as I already mentioned in the next video, we're going to inject this DAO in our repository. So for this video, that'll be all. 15. Introducing with Dagger-Hilt Library: Hello there and welcome back. In this video, I'm going to introduce you with dependency injection library called the dagger hilt Savoir Hilti is dependency injection library for enjoy that that reduces the boilerplate of doing a manual dependency injection in your project. Now, doing a manual dependency injection requires you to construct every class and its dependencies by hand. Now, healed provides a standard way to use a dependency injection in your application by providing containers for every Android class in your project. And they're managing their lifecycle automatically. So a Hilton is built on top of their popular dependency injection library called the dagger to benefit from the compile time or correctness runtime performance, scalability, and Android Studio support in their dagger provides. So while, when starting with a hill 31st thing you need to do is a Hilton enjoyed the Gradle plugin to your project level gradle build file. Then after that you need to apply a Gradle plugin and add the following dependencies in your application module or Gradle build file. So every application that uses a Hilton must have application class annotated with the hilt Android app annotation. And the denotation will trigger Hilts co-generation, including a base class for your application that serves as the application level dependency container. Now, these are generated heel component is attached to our application object's lifecycle and provides the dependencies to it. Additionally, it is the parent component of the app, which means that other components can access the dependencies it provides now or after you create and the annotate your application class with the hilt or Android app annotation. Next, you need to annotate all your activities fragments in other enrolled classes with our Android entry point annotation. So of course you only need to annotate them if you are planning to inject. Some classes are inside them. For example, if you are planning to inject there are some classes in your fragment, then you would need to annotate your fragment, but also the activity that is hosting that same fragment because the fragment is located inside an activity. Now, since we are using a jetpack composed to build our application, we are not going to have fragments, only a single activity. And because of that, we will only need to annotate our activity with the this Android entry point annotation Savoir Hilton currently supports the following Android classes application of EU model, activity, fragment, view, service and broadcast receiver also enjoy entry point or annotation will generate an individual, a hill component for each enroute class in your project. Next, let me introduce you with one important concept called the binding. So while when you want to inject a certain type, you need to tell hilt how to provide an instance of that type is a dependency and are binding basically contains the information necessary to provide instances of that type is a dependency. One way to provide the binding information to healed is a constructor injection. And the perimeters of an annotated constructor of a class are called the parentheses. And in this example, my adapter class, Here's a nice service, is a dependency. Therefore, hilt must also know how to provide instances of that my service. Okay, so next, let's talk about the hilt modules. What are healed modules exactly? Well, they are basically a place where we define how to provide instance of a certain type. Now, sometimes our type cannot be constructed, injected, and this can happen for a multiple reasons. For example, uh, you cannot construct or inject any interface. And also, you cannot construct or inject a type that you do not own. For example, you cannot take constructor inject some external library like a room or a retrofit for example, in these cases, you need to use the hilt module to provide healed with a binding information. The hilt module is basically class and that is annotated with the module annotation, which are in forms heel to how to provide the instances of a certain types. Also a you must annotate the Hilton modules which are installed in annotation to tell a hilt a which are Android class, each module will be used or installed in savoir dependencies that you provide in Hilton modules are available in all generated components that are connected with that Android class where you install the hills module. So for example, if you have specified to install module in our singleton component, then are all dependencies and which would they're fine inside that module will be available in the whole app. Now I'm going to list all components which you can use to install your modules in also a remember data installing a module into a component allows its bindings to be accessed as a dependency or other bindings in that component or in any child components below it in the component hierarchy. And on this image you can see the actual component hierarchy. So on the top of the component higher here we have our singleton component, which means that they're all bindings which are installed in this singleton component can be accessed throughout the whole application. And because these are singleton component that is on the top of the hierarchy, that means that the bindings that singleton component can be also accessed from other child components like a service component, activity component, ViewModel component, Freidman component, and so on. But if you scope your bindings to, for example, it's a foramen component, then the bindings from that component cannot be accessed from the components up in the hierarchy. So if you install some bindings in a foramen component, for example, then those bindings cannot be used in this hierarchy above the fragment component. Now, there are also two more important the annotations are used in a hilt modules. The first one is called the Bayesians and other one provides. So the first one that binds is mostly used when you want to inject any interface in because you cannot construct or inject and interface, then you need to provide healed with a binding information by creating an abstract function annotated with their binds annotation inside a hilt module. So the binary notation and we'll tell the hilt which implementation to use when it needs to provide any instance of an interface. And the return type of that abstract function will tell the hilt what interface and the function provides instance off and the parameter is inside that function will tell hilt which implementation to provide. So the hilt module name there, my module is annotated with the install in a notation where we have specified activity component because you want the hilt to inject that dependency into example activity. And this notation means that all of the dependencies inside the module are available in all of the applications activities. Now, interfaces are not the only case where you cannot construct or inject a type. Constructor injection is also not possible if you don't own the class because it comes from an external library like her room retrofit, okay, HTTP client and so on. Or even if instances and must be created with the builder pattern. Now those are the two main reasons why you need the second important annotation called provides Sowell provide sanitation is used to specify bindings for a specific classes that you don't own and that the return type of a function annotated with provides a notation will tell the hilt wild-type it needs to provide an instance of the function parameters will tell the hill that the tendencies of that corresponding type also one important thing. So a hill that will execute in the function body every time it needs to provide an instance of that type, which we have specified, Of course. Okay, so those were some important basic cell which you should know when we're working with this dependency injection library. It's a very convenient library and every beginner out there, it can use it without a problem. Now if you have any questions related to this library or dependency injection in general, then are feel free to send me a message and I'll gladly answer all your questions. And for this video, that LBO. 16. Create ToDoRepository: Hello there and welcome back. So why in the previous video, we have a successfully set up our dagger hilt library. In our project, we have created our hilt module where rehab describe that, how to provide the instance of our room database builder and also how to provide our two Dao. Now in this video, it is time for us to create the repository. So inside our data package, we're going to create a new package. So let's create here a new package, name their repositories. And here I'm going to create a new Kotlin class named the to-do repository. Are okay, perfect. So our incidence, the repository, we're going to inject the Tao or our data access objects. So here I'm going to use the Inject annotation and let's use a constructor keyword in here. It's called a private Val to do Dow and the type of course, so this variable should be two down. So a dagger hilt library knows how to inject this to-do Dow, because inside our database module here we have created a function which has a return type of a to-do Tao. And basically, our hilt library is using data return type to decide which one of those provides function should be injected into our repository. And since here we are injecting a to-do Dao, that's how our day or hills library knows to provide this instance. So now inside this repository, I'm going to use this DAO to access all those functions which we already have in this interface. And of course, this repository later will be injected inside the view model. And the view model we're going to have access to all our SQL queries, which we have already made. So first here I'm going to create a variable named the get all tasks. And the type of this variable should be flow. So Java or sorry, Katlyn coroutines dot flow in here I'm going to use a list of two tasks. So to do tasks are okay. And here I'm going to call our two dow dot, get all tasks. And of course if I select a dysfunction and press Control B, then it will lead us to this dao interface and dysfunction or this SQL query. Next here I'm going to also create two more variables, and this one will be named as sort by a low priority. And the type should be again a flow of a type of our list, a to-do task. And here I'm going to call a to-do Tao, which we have injected. And then I'm going to call a sort by a low priority down below, I'm going to create one more variable this time it will be sorted by a high priority. In here I'm going to just call a different function. So this one. Next I'm going to create one function called get selected task. And this function will basically have one parameter and that is a task id of type integer. And it will return a flow of two tasks. So it will return just a single task. And inside the body of this function, we just want to return the dot, dot I get selected task and here we want to pass that ID. So task ID from the parameters of this function or k. Next I'm going to add a new function. So here I'm going to suspend keyword and it is first function we are not using suspend keyword because of this function is returning a flow and the flow is asynchronous data stream. So here I'm going to create a new function called the EDR task. And this function will take one parameter to task. And from here we're going to just call our todo down and its function at dusk. And here of course we want to pass our two task, the perimeter. So this function perfect. Next Let's call another suspend function named the update task. This function will also take two task as a parameter. And here we also want to call our Dao up the task. And here it's best to task are okay, Perfect. And next time we will just copy this function down below one more time. And this function should be named delete task. It will again take the same parameter and we're going to just call a different function. So delete task are down below. I also want to copy this function one more time and I'm going to rename that to delete all tasks. And this function will have no parameters. And we're going to just call a different function. So delete all tasks are okay, perfect. And then finally I want to create another function. So this function will have no suspend keyword because it will return flow and this function will be called the search. A database. It will take just one parameter and that is a search query of a type string. And of course it will return a flow of our list of 20 task. So let's return here to down dot search database and let's pass here a search query. So now basically we have used the, all those functions from our to-do down. And we have successfully created our to-do repository by injecting this dao from our health module. And later in this course, when we create a view model, we will need to inject this repository in Data View Model. And also then we're going to add one more annotation called the ViewModel scoped because that annotation is also a part of a day or Hilton library, which will allow us to scope the instance of this repository to the life cycle of a ViewModel Savoir for this video. And that'll be all. 17. Create SharedViewModel: Hello there and welcome back savoir. In the previous video, we have successfully created our to-do repository, and also we have successfully set up our dagger heel-toe library. So the next step before we actually set up our navigation component, I want to create a view model in which I'm going to inject this repository so that the new ViewModel will be actually a shared view model, which means that it will be shared across multiple composable screens. And in our case, we're going to have three composable from richer. The first one will be just a simple splash screen. Nevertheless, that are shared view model will be actually shared between two composable screens, at least composable and the task composable, which we are going to create the in some of the next videos. For now, what I'm going to do here, I'm going to create a new package inside our UI package in here I'm going to name that package view model or a view models and insert data package. I'm going to create a new Kotlin class, and I'm going to name this class shared view model. So the first thing here I'm going to inherit from a view model. And the next thing we need to actually inject our to-do repository inside their share ViewModel. But before we actually do that, we need to go to our to-do repository. And here I need to add just one more annotation, which is ViewModel scoped. And this notation is part of a dagger Hilton library, which will basically tell that the instance of our to-do repository will be alive as long as the shared the view model in which we are going to inject this repository. So let's open up our shared ViewModel here, and now let's inject here our total repository. So constructor in here and just add a private Val repository of a type of a to-do repository. And now we have a successfully injected our shared ViewModel with this repository. There is just a one more thing which we need to add here and that is hilt view model annotation. So if you want to inject your view model, then it is important to actually add this hilltop view modelling notation so that our dagger hilt, the library, can I generate some classes behind the scenes like a ViewModel Factory and so on. Nevertheless, you don't have to worry about those things, so they are healed. Library will take care of everything. And now inside our shared view model, I just want to add a few lines of code. But later as we make progress, we are going to add some more coding, said our shared V-model. So the first thing here, I'm going to create a function named I get all tasks. And inside this function I'm going to a ViewModel scope. So this is basically a coroutine scope tied to our life-cycle of our shared view model. And now I'm going to launch a coroutine. So let's call our repository, which is a total repository. And from here I'm going to call a ghetto tasks and I'm going to collect the value. And on top of that, I'm going to also add two more variables. So the first one will be a private variable named the underscore or tasks, and it will have that type of immutable state flow. So Katlyn coroutines flow in here. I'm going to just add the list of todo task and they're here for now default value will be an empty list. So we can just satisfy the type of this variable. And down below I'm going to create another more variable named all tasks without the underscore in the type of this variable this time should be a state flow of list of to-do task. And we're going to just get the value from our underscore task. So inside our get all tasks function, I just want to update the value of this underscore tasks variable to the value which we are going to get from this Flow. Sowell, That's all I wanted to add inside our shale ViewModel for now. This is basically a function which we'll call our repository and it's variable named I get all tasks which will then call our to-do Tao and it's SQL query. So basically this function will retrieve all the tasks which we have inside our database table. And it will assign that data to our underscore or tasks variable. And of course this is a second variable without underscore will be publicly exposed to our composable, where we are going to observe that. And they get notified from our composable whenever the value of this underscore tasks variable changes. So you will see about that later. For now, it is important that we have created our shared view model. We have injected our to-do repository inside it. And we have also created the one function which will basically fetch all tasks from our database table. So for now it will be enough. And the later as we progress throughout this course, we will add some more code instead associate V-model. So for this video, that will be all. And in the next video we are going to setup our navigation component. 18. Introducing with Navigation Component in Jetpack Compose: Hello there and welcome back. In this video, I'm going to introduce you with the navigation component in our jet precompose. Now, if you are already familiar with the navigation component in general, then it will be easy for you to adapt some changes which were introduced in Azure AD pre-compose. So the first thing you need to forget about the navigation graph in an XML, because when using a jetpack composed, we are not going to need the any XML files. Instead, everything will be declared inside a Kotlin file. Now it's almost the same as using navigation component to it, the traditional view system, we are still going to need the nav controller to handle the navigation inside our application. We are still going to need the nav host, the navigation graph, and we are still going to use arguments to pass some values between our screens or composable. However, there is one more thing which we need to forget and that is sending whole objects between composable. I mean, you will still be able to do it about the official documentation says that you should send only primitive values in arguments, like an integer, strings and so on. And instead of passing the whole object, you can just pass, for example, the ID of that object. Then in the receiving composable, you can take that ID value to retrieve the whole object information from the database, for example, now, when you need to get a reference of a nav controller in your composable, then you need to use a function called The remember, nav controller. And you should create a nav controller in their place in your composable hierarchy were all composable data needs to reference it, have access to it. Now, ethernet controller must be connected with their one nav host. And the host will basically our linker, all your composable destinations, which we'll define in it with the nav controller so you can actually navigate between them. And when creating a nav host that you need to pass a name controller along with the start destination of your choice. So we're destinations inside your navigation graph, or an F host are defined inside. They're composable functions called composable. And each destination in your navigation graph should have a route. And the route is a simple string which defines the name of your destination along with the optional or required arguments Savoir to navigate to a composable destination in your navigation graph, you must use the navigational function from our nav controller, that the navigate function will take only a single string parameter, which represents a destination route. So you should only call an aggregate function as a part of our call back. And they're not as a part of your composable itself because we want to avoid calling this Navigate function on every recomposition by default. And navigate function adds your new destination to the back stack and you can modify the behavior of a navigated by attaching additional navigation options to your navigate the function. Now, when it comes to passing the arguments that between destinations, if you want to declare in argument, then you need to add an argument placeholder along with the route of that same destination on which you are planning to use that argument. Now before I show you some R code examples, you should know that there are two different kinds of arguments. The first one are required and the second one, optional argument. So there is a slight difference between those two kinds of arguments. And first, let me show you how to declare a required argument. Now, let's say you have a destination or with the route home, and you want to add an argument to that destination within that type of an integer. The way you define that argument is a route name slasher argument placeholder. And that argument placeholder should hold the key of that argument. For example, we can name the key of that integer value, a number. Now, that's how you can define an argument. And if you want to extract or read that the argument value, which will be passed to that home composable. And then you need to use the nav back stack entry object, which is available in the composable lambda. And finally, when you are sending that argument from some other composable, then you need to pass that the value inside a Navigate function, along with that the route name of the destination which you are navigating to. Now those were some required arguments examples. Now let me show you how optional arguments work. So our optional arguments differ from a required arguments in two ways. First, they must be included there using a query parameter, a syntax like a question mark, argument, key equal, and the inner brackets, the actual value which you want to pass. And the second, they must have a default value set or a heaven of ability equal to true. Now, even if there is no argument passed to that destination, our default value will be used instead. So basically a required your arguments means that you need to pass a certain argument composable destination every time you navigate. And the optional arguments means that you can't pass some arguments to our composable destination, but it's not required. Now in our application, we are going to use the require the arguments only, but we could use optional arguments as well. Nevertheless, I might add some optional argument in some update videos for this course just to show you how it works. Anyhow, I'm going to think about that. And then now those were some basics about the navigation in a jet decompose. So from the next video, we are going to start implementing navigation component in our project. 19. Setup Navigation Component: Hello there and welcome back. In this video, we're going to start setting up navigation component in our project. So if you are already familiar with the navigation component, then you already know that an app controller is the central API for the navigation component. It will keep track of the back stack of composable that make up the screens in our application in the state of your screen. Now, when creating an app controller, you should create it in the place in your composable higher here, we're all composable that it needs to reference it, have access to it. And in our case, that will be a main activity. Now each and every controller must be connected with one nav host and the net host will connect nav controller with the navigation graph, which contains all composable destinations in our application. In our case, we're going to create three composable screens. The first one will be at least composable where all our tasks will be listed. The second one will be a task composable, which we will be able to modify existing tasks or create a new one. In the third one will be a splash screen, but we will add that third one at the end of this course. For now, we will stick only with those two composable and don't be scared that with all of that theory, which I have mentioned earlier, everything you will make more sense when we actually start coding. So the first thing, which I'm going to do here, I'm going to create here a new package. So let's name this package navigation or came in incidence navigation package. I'm going to create a new Kotlin class and I mutant in this class screens. So this class will have only one parameter and that is an app controller. But in order to use the nav controller, we need to add the one dependency for our compose navigation. So let's open up our Gradle build file. And down below I'm going to just add here one more dependency, compose, navigation, our k. And now I'm going to just sing the project. Okay, So now we can close that. And here let's add the nav controller of a type of a nav host controller. So inside this class for now, we are going to create two variables, and each one of those variables will represent one screen or one composable screen. But before I added the right here, I need to create here one Kotlin file in which I am going to create a one E&M class. So inside our util package, I'm going to create a Kotlin file or I'm going to create here an enum class. So this class will be named the action. And this action or enum class will represent some of the actions which are we, we are going to trigger with our database table. So the first entry will be add, the second update. The third one are the elite. The fourth one will be delete underscore all. The fifth one will be undo, and the last one will be a name that no action. So we're going to use this enum class to actually pass the action from our task or composable to our earliest screen, or at least composable. So you already know that our least composable will basically at least the all our screens, while our task composable will contain all the components that we need to actually trigger some of those actions about. Instead of triggering those actions directly from our test composable, we want to pass some of those actions from our task composable to our list composable. And that's why I needed to create here this enum class named action. So now instead our screens class, I'm going to declare here one variable named the list. In this variable we basically take an action. So this one, the action which we have just created, and then we would just hit return a unit. So basically nothing. And then here I'm going to just use that action to actually navigate. So we'll introduce a nav controller, then navigate. And here we need to pass the route, and the route will be list slash in here. I'm going to just use that action. So let me just rename this ON action. So action dot name. So basically this variable will take action, which we are going to pass from our test composable. And there we're going to use that same action to navigate to our list composable. And that action will be passed as an argument to our list composable. So our least composable will have a one argument which will be action. And our test composable will have argument type integer. And that the argument inside our test composable will represent the ID of our selected task. So you will see about all that later when we actually start implementing some more code. Now all of this might be confusing at this moment, but everything will make more sense later when we actually add some more code. And I'm going to explain all of that again once we complete our navigation component and setup a few more things. So the second perimeter of this and navigate function from our nav controller is NAV options, so Builder, so we can access that. Perimeter through the lambda n here also I want to call our pop up too. And the here basically I need to pass a route of my destination to which I want to go to. And in this case we want to go to our list composable. So we're now instead of hard-coding that route here, I'm going to just go to our constants object in here. I want to make two more constants. So the first one will be list screen. And here we are going to write our list slash. Then inside parenthesis I'm going to add an action. So that will be the key of our argument and they're down below. And we'll do create one more constant task screen. And here I'm going to add a task which is the name of our composable screen, then a slash task ID. So here you can see that the name of our composable screen is separated by this slash with the argument. So here we have a route name slash argument and that's how you can set up your composable screens. So now let's go back here to our screens in here I'm going to type a list screen, and let's just import this constant. And also here I'm going to type inclusive equal to true. So that means that whenever we navigate from our task composable to our list composable, I want to pop up to at least screen and basically remove our test composable from the back stack. That down below I want to create one more variable name that task. And this variable will take any integer value. So it will be a task ID which we're going to pass from our list screen to our task screen. So basically whenever we navigate from our list screen to our task screen, we don't want to pass the whole task object to our test composable. Instead we just want to pass the ID of that selected task. And then from our task composable, we want to request that task object from the database. So don't worry if all of this sounds confusing at the moment, everything will make more sense later in this course. And of course, again, we're going to get back to this same class and I'm going to explain you everything all over again. So here we're going to just return a unit and I'm going to call a nav controller to navigate. But this time we are navigating to our test composable. So let's name this task ID. And here I'm going to write double-quotes, task slash, task ID, and the hearer inside this nav options a builder, we are not going to put anything because whenever we go from our list screen to this test screen, we don't want to pop off our list screen from the back stack, we want to keep it alive. So the next thing inside our navigation package, I'm going to create a new Kotlin file name, the setup and navigation. And here I'm going to create a new composable function named setup navigation. And this function will take two parameters. For now, we are going to add the only one. And that is a nav controller of a type of a nav host controller. And inside this function, I'm going to add that one variable named a screen. And here I'm going to use the remember. And here I want to remember a nav controller because I want to pass that test. Same nav controller to our screens class. So let's best here a nav controller. And with this, so remember composable function, we basically want to save our bags stack of our composable screens throughout our application. And down below I'm going to call a nav host. So this is composable function in which we need to create our composable screens. So this function accepts two parameters. The first one is the Nav controller, and the second one will be a start and destination. So a star destination for us will be at least the screen. And that's a constant which we have already defined. The inset our constants are objects, so let's just import that right here, or skeleton just put in those arguments in a separate lines. Okay, now inside this scenario host, inside this nav graph or builder, we need to define our composable screens. And as I already mentioned, we're going to have a three screens, but for now we're going to focus only on to composable screens in that is at least screen and task screen or at least composable in the test composable. So instead of defining those are composable. So right here, I'm going to create here a new package, insert our navigation, and I'm going to name this package destinations. And inside this package, first I'm going to create a new Kotlin file named how least composable. So are inside our set at navigation, we need to basically call our composable function. And that function is actually defined inside this nav graph or builder. So if we try to call this a composable function right here, we couldn't do that. And that's why we need to create here an extension function on that and have graph and builder. So let's create here an extension function on a nav graph or builder. And let's name this function at least composable. And then now here we will be able to call this a composable function. Okay? So this function, as you can see, assets are multiple parameters. In the first one is the route. So the route is already defined inside our constants are objects or just import that. And the route for this Sally's composable is just. This a string solely is the name of our composable slash argument, which is actually in this case. And the second parameter which we are going to define here is arguments. So this argument's is defined in a list, so that's why we need to call our list off. So a list of a nav argument in here. We need to specify the key or the name of that argument. And in our case, that argument is named the action. But of course we can create here a new constant for that. So let's open up our constants object and let's create here a new constant. So a list the argument key and it will have the value of action. And down below I'm going to define a task argument key which will have the value of a task ID. Okay, we're going to need that later. For now, let's go back to our list composable, and let's just specify that constant argument key, okay, perfect. And the next thing here, I also want to set that type of this argument. So let's call here a type and lets us specify here nav type, string type, because the type of this argument will be actually a string. So our Elise composable or our list screen, we'll have a one argument of a type string. In that argument will be action, and that action will be passed from our task screen whenever we trigger one of those actions. So you will see about that later. Now we have defined the everything we need for our composable function or for our list composable. So for now I'm going to leave this composable empty. But later in this course, we are going to start designing our first at least composable. And now that we have created this list composable function or this extension function or an error graph builder. Now we can open up our set of navigation, a file in here, incident net host, we can call that least composable. So now we're going to create the second decomposable screen, which will be a test composable. But before I do that, let me just here add the one parameter in the perimeter will be called the navigate to a task screen. And this will be a Lambda which will take an integer value and it will just return a unit. So now from our setup navigation of file here, we need to pass that argument or that parameter. So they're just pass here and navigate to task screen in here I'm going to call this screen or variable from the top, and I'm going to call task. So that way we are basically calling this task a variable from our screens class. And as you already know, these screens class that contains nav controller, which will immediately navigate us to our test composable with the specified ID. And of course we're going to pass that ID later. For now, let's just create here another destination, and I'm going to name this file task composable. Let me just copy the same thing from this waste composable and I'm going to just change a few things. So let's rename this to task composable. And in this case, we're going to change this to a navigate to our list screen. And it will take action instead of integer r, k. So this one, and here for the route, we're going to specify a task screen and the argument will be Task argument key. A type will be an integer. So now we can call this Test composable from our set of navigation here as well. So a task composable. And here I can just pass and navigate to the screen. And I can call a screen shot list. And this will basically trigger our list variable here, which takes, as you can see, an action and it navigates us to our least composable with the specified action. And from our test composable that action I will be obtained there later. So before I end this video, there is just one more thing which I want to do. So I want to call now this setup navigation function from our MainActivity. So let's open up our MainActivity. So the first thing I want to add here one variable, so private in it, var narrow controller of a type of a nav host controller. So the S1 and the inset, our set content or a to-do compose a theme. I want to initialize this nav controller variable. So remember nav controller, okay, so that's composable function you use to actually set up a nav controller. And then down below I'm going to call our setup, our navigation, which we have already made. And let's pass the center controller right here. So from our main activity, we are calling this setup navigation function, which is this one. So I can just rename this file to something different. So let's just rename this to just simple Navi archeologist to refactor it perfect. So this navigation file contains this set of navigation function. And inside this navigation function we have this variable which will just keep track of all our composable. And the down below we're calling a nav host. And inside this nav hosts we are basically they're finding our navigation graph. And inside our navigation graph, we have there find the tool composable or two screens. The first one is the least composable in the second one is a task composable. And each one of those comparables for now contain a one parameter. And that is a Lambda which will contain action. For our test composable and an integer value from our list composable and inside each one of those extension functions, so which we have created, we have called this composable function, which is actually the part of an aircraft builder. And here we have defined the route of each our composable screen. So the silliest composable have a route of least slash action and our test composable have a route of a task slasher, task ID. And everything behind this slash is actually an argument, and that's how you define this required argument. And after we have defined the route in each one of those composable, we have also defined the actual argument which we yours. So in our case, our least composable will have a one argument of a type string. And the key of that argument is this constant. So action and our test composable will have a one argument of a type integer, which will have a argument key or for a task ID. And we have defined all of that right here. So I know that it's a little different to set up navigation component inside the jetpack composed than it was with our traditional view system. Anyway, I know that this is a lot of information for you to process. Just be patient. And in the future videos, we actually start adding some components to our screen, then everything will make more sense. Nevertheless, if you have any questions, feel free to send me a message and I will gladly explain that everything you need to know. So let's just recap once again and what we actually did inside this video. So inside our main activity, which is the main entry point for our application, we have created the variable and have controller, and that the nav controller is passed to our setup navigational function, instead our navigation file. And we are using that nav controller to actually remember all our screens, which we have defined inside our screens class. So this is screens class contains two variables, and each one of those variables are taking either action or integer value, and they are using that value to actually navigate to different screen. So this is the first case. So we are navigating to our released composable and we are passing that action as an argument. Also down below, we're just using this pop-up to function to pop up to a given destination. And here we are using inclusive to true so we can actually remove our test composable from the back stack and we can just leave our least scream. And down below we are using the route to actually navigate to our task composable. And of course we are passing this test ID as an argument. So inside our navigation, we have defined the two composable or a two screens. The first one is a list composable in the second one is a task composable. And inside each one of those, we have there find the route and the argument. Here we have defined the key of that argument. And down below we have defined the type of that argument. So I know that this is a lot of information for you to process. Just take your time and the later when we actually add some more code to our project, I'm going to explain everything all over again so it will make more sense. And now I think that we should stop this video and we will see each other in the next one. 20. List Screen - FAB: Hello there and welcome back. So we're in the previous video, we have a setup, the navigation component. We have created a navigation controller inside our main activity, whichever added the nav host and also specified the two composable screens at least and the task composable plus whichever declared what kind of arguments we want those two screens to have. So the first list composable screen will contain an argument of a type of action, and the action is in an enum class which we have already made. You will see the inaction later in this course and our second test composable. And we'll have an integer value argument which will represent a task ID. And the data task ID will be passed later from our list composable whenever we navigate to our test composable. Now in this video we are going to finally start to designing our list screen. And before we start designing that at least screen and they get into the coding, first, I just want to shortly introduce you with a scaffold. So you might have heard already about the scaffold, either from a jetpack composed or even a flatter. So a scaffold is one amazing composable function which comes with the material library. And they're basically scaffold that will allow us to implement the basic material design layout structure in our application. And that basically means that we can easily create some material components like floating action button, bottom bar, top bar, and navigation drawer and just pass those are components directly in the scaffold, which will then take care of everything and place them in their original position scaffold that will take care of everything in order to make those components work together as expected. Okay, so now enough talking. Let's start and add that one as scaffold composable function inside our list composable. Well, as I already mentioned first, we are going to start with our list screen, or at least composable. So let's just close everything from here except this MainActivity, or we can just close that as well. So our inside our list composable here, we need to start actually designing our screen. But of course, instead of designing our whole screen right here, directly inside the cell is composable Kotlin file. I want to create a new package inside our UI. And it's named this package screens. And inside this screen I'm going to add a new package called the list. And inside the list I'm going to create a new Kotlin file, name the list. So just press enter now K. And let's create here a new composable function. So function name the earliest screen, and therefore now this Sally's screen will have only one parameter and that is this and navigate to task screen there lambda as we have that in our list composable, solid just to edit right here. Okay, And now from our list composable, we can call here at least the screen, and we can again, just a specified data navigate to task screen because of this lambda or this integer value will be located deeper in our list screener composable function. And here we just need to pass that lambda to satisfy the parameters of our function. Nevertheless, let's go back to our list screen. And down below also I'm going to create one composable function, but this time this will be a preview function in which we are going to preview our screen. So let's name this function, at least screen preview now k. And here we're going to just call our list screen from above in here as a perimeter, we're not going to specify anything. We can just add this empty parenthesis just to satisfy the parameters of this function. Okay, so for the preview, it's not important to actually add here is some value or anything. It's just important to satisfy the parameters of the function which you are calling this preview function. So now inside this list screen, I'm going to finally add a scaffold. There it is. And if I press Control P in the parameters, so this scaffold function then you can see that this function accepts many different parameters and we can even click on this scaffold and press Control B to open up the source code of these composable. So now you can see that the this composable scaffold accepts many different parameters from a which a few of them are actually composable. Like a top bar, bottom bar, a floating action button, draw our content and the content. So in this specific video, we are going to design a floating action button so I can just show you how this screening will actually look like. So we'll just close that for now. And we can even remove the body of this scaffold function because we're going to only need to pass some parameters inside this function. So first, I'm going to specify here floating action button, so here it is. And here inside that we need to create our floating action button. So you can see that we have a warning here in our scaffold function because a mandatory perimeter is the content. So here we also need to satisfy that the parameters, so content. And I'm going to leave. Empty parenthesis here in our content because at this point we are not going to define any content. We're going to do that in some of the next videos. For now, we're going to focus only on a floating action button. So down below I'm going to create another composable function named the least fab. And inside this function I'm going to define a floating action button. So we already have this composable function from material library. So we can just call this material floating action button in here. As you can see, it's a default parameter is onClick. So for now I'm going to leave this onclick empty and the inset, our floating action button, we need to add one icon. So let's call icon composable function. And here we need to pass a painter or an image of actor. So I'm going to pass imagery vector, and I'm going to call icon or icons, that field. So I can use a field icons dot add our case. So I'm going to use this Add icon. And also let's separate those arguments on a separate line. In for the quantum description, we can just pass something that will describe this icon. In this case, we can just type Add button. So whenever we press Control P on this icon composable function, you can see that this icon composable function has a three different constructors. And the third one, which we are using have this image of vector object. First perimeter content description as a second parameter, modifier as a third and a themed color as well. Of course, those parameters are not mandatory, so we don't need to specify them if we don't want to. And here we have used these icons object to actually specify some default icons, which we have by default. So there are different kinds of categories for icons, like a field outline around it to tone Sharp and the default one which is actually a field. So now we have used the field icons and we have selected this Add icon. In this Add icon basically represents so symbol. So now this list FERPA function will have a one parameter and that is this and navigate to test screen Lambda. So let's add that lambda right here as well. And I am going to call this navigate to task screen. And I'm going to pass an integer value from our floating action button. So basically whenever we press this floating action button, we want to navigate our user from our list screen, or at least composable to our task, composable. So whenever we click this floating action button, we are not selecting any existing tasks. Instead, we want to create a new one. So in that case I want to pass here an integer value. So let's call this and navigate to test screen. Here I want to pass a minus1. So basically whenever we press our floating action button, we want to pass integer argument to our test composable. So if you recall inside our screens class, we have declared that task variable. And whenever we navigate from our list screen to our test screen that we need to pass this task ID, okay, and data task ID is actually this number in the reason why I have set this minus1 number on our floating action button is because in this case we are not selecting any task, but later from our lazy column or from our list of tasks. Whenever we select one of those tasks, then we're going to pass in the real task ID. So this is a task ID in our test composable will be useful because depending on what number we get from our list composable, we're going to decide whether to display one or another top bar because inside our test composable, we're going to have a two different top bars. And depending on this integer value, we're going to display only one of those. So you will see about that later. For now, it is important that we have satisfied that navigate to task screen integer from our floating action button. And now from our scaffold inside of our list screen, we can just call this the least FAD. So we'll just call list fab in here. We can just pass this navigate to task screen just to satisfy the perimeter of this function because we have already passed in this number from our list fab. And because we have specified that this number inside the earliest Fab, we will send that number up in our composable hierarchy to the list screen, and then from the list screen to our list composable. And then from our list composable right here and here as you can see, we are calling that screen and that screen along with this nav controller, actually doing all the navigation. So don't worry if all of this still sounds confusing because there are more pieces that we need to put together in order to make all of this more understandable. And now that we have successfully created our list floating action button, now let's just open up this preview so we can see how now this scaffold, or the smallest screen, will actually look like. So let's just click here, build in a refresh, and now there it is. So here in this preview we can see our list screen because the incidence of preview function down below we have called our list screen. And inside our list screen, as you recall, we have a scaffold, and inside the scaffold we only have a floating action button for now. So now you can just assuming here to see all the components even better. So for now, our floating action button is using this black color for our icon, and we can change that easily. So here inside our icon we can just specify one more parameter and that is a thinned. And here I can just specify a color and white. So now let's rebuild and refresh our preview so we can see the change. And now our icon should change the color to white. Okay, so there it is. We can just zoom in and scroll down below. So there it is, now the icon and have changed the color. So before I end this video, I just want to make one more change as well. So you can see that incident or at least fab composable function. We have written here a content description that says Add button. And it's always a good idea to place those texts inside the strings XML. So now I'm going to remove this string and I'm going to go to our resource directory. Then down below values, then our strings. In here I want to add one more string. And here I'm going to write Add button. And let's put that text right here. So add a button. They're from our list screen. The way we can call this string, we can just use this string resource composable function in here. We can just pass the ID of that test string from our strings.XML. So let's type R dot string syllogistic important, these are so string dot add a button. Okay, perfect, and now it looks better. So now we don't need to hard code those values directly here. We can just put them all in our strings.XML file and therefore this video that will be all. So now we have successfully the scaffold to our list screen. We have also created the floating action button, and we can also just change this parameter to say something different. For example, let me just press here a Shift F6, and I can rename this to on a fab clicked so it can look even better. So whenever we click on our floating action button, we're going to send this value, this integer number, up to our composable hierarchy in our earliest composable. And then from there we can just call our screen task The basically navigate to our test composable. So for this video, that will be all. And now you should have seen how to use a scaffold. You can see the two. We can easily put our floating action button inside our scaffold, and it will immediately place that button on the bottom right corner where our original floating action button should be. And it will be the same thing with a top AB bar for example. So whenever we here at the top bar, it will be immediately put on the top of this screen. So you will see about that in some of the next videos, and therefore this video, and that'll be all. 21. List Screen - Default List App Bar: Hello there and welcome back. So we're in the previous video, we created our Elise screen composable function in which we have put the scaffold. And also there we have designed our first component, which is a floating action button, and this is our preview. So this is how our LED screen, and it looks like so far. And there now let's suggest that run our application so we can just see if everything's going to work fine. Okay, So while we were running our application, I have received their one error. And the reason why is because I forgot to adhere one more dependency for Maya dagger heels librarian. So when we could just paste here One more dependency for a hill compiler. And now let's sing the project and let's run our app once again. Now let's run our app again, our case. So there it is. As you can see now in our application, we can only see our a floating action button. And in the previous video we have added that at least the floating action button. And this at least screen is a quote from our list composable. So the next thing which we need to do here, we need to create our top bar, or a formerly known as the ActionBar. So here in our scaffold, we can just call a top var. Okay, so inside this top barrier, composable lambda, willing to specify or a pass our top bar, which we are going to create right now. So first the inset, our UI screen, so least package and when to create a new Kotlin file. And I'm going to name this file, at least at bar arcane. So let's create here a new composable function, at least the app bar. So before I continue with the code that there is one more thing which I need to mention. So our list screen will actually have two different top bars. The first one will be a default at least m bar, in which we are going to have three different icon buttons, search icon, sort icon, and the overflow icon to actually show one or drop-down menu. And the second that top airbags will actually be a searcher widget, which will be shown whenever we press that search icon from our default Oh, East air bar. And the first, we're going to start by designing our default, Alistair Barr. So let's here again create a new composable function. And we've done in this function the fault, at least the app bar. And here I'm going to call f bar composable function, which is a part of a material library sludge. Just a cool dad in here. We're going to pass them multiple parameters. So the first one will be a title in here, we're going to specify a text. So a simple text here, the texts that should say tasks are K. And then down below the second parameter will be a background color. In here I'm going to specify Material Theme, Colors, dot color primary. So now let's create down below one or more composable function. But this time our preview function, so composable and the purview. Ok, and let's name this function the fault list app bar per review. And here we're going to call this fault list their bar. So now let's check the preview clicker building a refresh our case. So this is how now our default Alistair Barr will look like. So basically this top airbag composable function will place this text on the left side where the original position of this title on top airbag should be. Then also we have specified here a background color. And now let's call this default Alistair Barr in cities list arrow function. And now this list AB bar function should be called from our list screen inside this top bar or scaffold. And now let's refresh and see how now this Elise screen and we'll actually look like our case. So now this is how our screen will look like. So this is our top bar and this is our floating action button. So by default, this scaffold that will place this list AB bar on the top in the place where top airbag should be our case. Let's just run our app now to see how all of that that will look like in our enjoyed the emulator. Perfect, so there it is. And now let me just switch to dark theme so we can see how now our application and will react to this change. So let's switch to dark theme and let's go back to our app. So now you can see that some of the colors say he has been changed. And personally, I don't like this purple color as my background color of top bar, and that's why I'm going to modify that. So let's go to our list barbara Kotlin file. And here we are going to change some values. But before that, let's open up our theme, our package, and let's open up our color Kotlin file. And so here I'm going to add that three more colors, light gray, medium gray, and dark gray. So we're going to use those colors in our project as well. And below those colors, I want to define a 2 extension properties. So let me create the first variable, which will be an extension property on our color or colors class. So Android X compose a dot materials. So this one, and I'm going to name this property top app bar, content color, and this should return a color. So AndroidX compose u i graphics in here I'm going to define a custom getter. So let's write here composable annotation, and let's add here a getter. So here I'm going to say if is a light is true, then I'm going to return a colored dots, white. Otherwise, I'm going to return this light gray color. So basically now we can access this top Ibarra content color property by calling our material fema object. And let's just click on these colors class and let's press Control B so we can open up the source code. So this color's class basically contains all our material colors, and those colors are available in our project by default. So that's why I wanted to create a new color. And based on our device theme, we're going to choose either a white or light gray. So if in our Android device we're using a life theme, then the color of this variable will be white. And if we are using a dark theme, and then the color of this variable will be light gray. So now let me just access this color from least a bar in here as a color perimeter of our text, I'm going to specify Material, Theme, Colors, dot top bar or top bar content color. Let me just put those arguments on a separate lines. So now as you can see, we have access to this variable which we have made from our material theme object by calling these colors are variable and instead our color causing file, we have defined a custom getter for this variable. And also down below I'm going to create one more extension property. And this time I'm going to set the name to top app bar, background color in here. I'm going to add purple 500 if we're using the Life theme and the color and black if we're using a dark theme. So now let's go back to our list AB bar and a here for the background color, I'm going to specify a top bar, a background color. So depending on our theme, we're going to have a different background color for our top bar. And also these are texts color will change as well. So now let's run our app once again so we can see the change. So now we are using a dark theme, and as you can see, the background color now of our top bar is actually black and the text color of this subtitle is actually light gray. In the light gray is almost the same as white, but there is actually one difference. It's a little lighter. And now let's switch to a life theme so we can see the change, our case. So now as you can see, we had this purple 500, which is actually a primary coloring our material theme and also a white color for our text. So that's how we can easily adapt our application design. In the light and dark theme. This is just a convenient way of defining our own material theme color properties. And before I end this video, I just want to make one more change. So you can see that our status bar in dark theme not changing the color. So as you can see, everything has been changed except this status bar color. And now I'm going to change that. So to do that, we can easily open up our resource directory, then our values, then our themes in here we can open up both of those are themes are XML files. The one is for our light theme, and the second one is for dark theme. So you can see that the both of those themes XML files have this status bar color already set. And now I'm going to change that value from the Senate version in here. I'm going to just add the color black. Let's now clause all of that. And let's run our app once again. So now the status bar of our application should change the black color when we are using a dark theme. So there we go. Now, our application looks even better in the LED switched life theme so we can trigger it out now. Okay, so everything works perfectly fine. So for this video, that'll be all in the next video, we're going to design a top bar actions. So if we open up the source code of this setup air bar, so press Control plus b. Then you will see that to this composable function are sets or action composable Lambda, which is using a row scope to actually define the, all our top bar actions. And that all those actions will be arranged in a row. And that row will be here on the right side of our top R-bar. So for this video, that will be all andy, the next video I'm going to show you how to define those actions. 22. List Screen - List App Bar Actions: Hello there and welcome back savoir. In the previous video, we have created our default least bar, and this is how it looks like for now. So in this video, we're going to create three actions which will be located on our default, Alistair Barr. And you already saw in the previous video, what are those actions actually are? So the first action will be a surge action, and that search action will actually trigger search bar, which we are going to create some of the next videos. The second action will be assort action, which will basically a display dropdown in which we can select, we want to sort our list them by a high priority, a low priority or a non priority. And the non priority will mean that our tasks instead, our list composable, will be sorted in their default or order n. Finally, the third action will be vertical menu or an overflow menu, which will basically these pledges that simple dropdown in which we can select delete all option. So you will see about that later and before we actually start designing those actions, there is just one more thing which I want to modify before we continue. So let's go to our list screen and down below to our list FAB. So for now as you can see, the background color of our floating action button will not change when we and go to our dark theme. So as you can see that the color will stay the same. And I think that for dark theme, this color is not actually appropriate and we should change that. So for that I'm going to go to our color Kotlin file and I'm going to declare one more extension property. And this time I'm going to write here a fab background color. So when we are using a light theme, then I want to select this teal to a 100 color, so default color. And when we are using a dark theme, then I want to change that to a purple 700. So now let's go back to our list screen. And also in our floating action button, I want to define one more parameter and that is a background color in here. Let's specify material, theme, colors, and background color. Okay, So now let's run our app again so we can see if this color will now actually change our k Perfect. So there you go. Now this color fits even better with our dark theme. Also, one more thing before we continue with our actions. Here, as you can see inside our list of FAB, we have a 1 RM the perimeter. And also we can specify here the name of that integer value. For example, I can specify here at task ID. So the main reason why I'm adding this name for this integer value is because that whenever someone else is reading our code, it will be more understandable this way. So now we can also add this a name for this integer value here as well. And also let's open up our list composable in here. Let's add that as well, our case, so there it is. And now let's go back to our list AB bar. In here, we can start creating our top bar actions. So now I'm going to add here one parameter which is called the actions. And if we check the source code of this top bar, then you will see that this actions composable lambda is using row scope to define all those actions. And here I'm going to create a new composable function. So composable function, and we're going to name this function the fault list, the app bar actions, or adjust the list A-bar actions or k. So this looks even better and the inset is composable function. I'm going to define three different actions. So down below the first one will be a search action. So let's create a new composable function called the Search action. So this function will take only one parameter and that is on search clicked lambda, it will return just the unit, of course, ended down below. And when do they find an icon button? And inside this onclick parameter, I'm going to just specify this on a searcher click lambda, and inside our icon button, we want to declare an icon. So it's called Icon are composable function and the hearing sense of the painter, I'm going to use the image of vector to call icons dot filled dot search. So this is a search icon. Let me just separate those arguments on a separate line. And the content description for this search action should say, for example, search tasks and the icon color should be. So let's say Material, Theme, Colors, dot top, app and Barbara content color. So basically the same color as our title here. Okay, and now let's call this search action right here, and incidents least the I-bar actions. I'm going to specify this same lambda. So just copied it here and pass this on searcher clicked. Okay, perfect. And now let's call this search bar actions from this narrow scope. Now k in here, just wanting to pass one parameter or one lambda, I'm going to pull that lambda in the parameters here as well. So we'll just copy and paste that here again. And here we can just specify on a search clicked. And I'm going to add here empty brackets so we can just satisfy the parameters of this function for now, of course, the actual logic which will trigger when we press this search icon will be implemented the later in this course. For now, we're going to just leave that as it is. And down below in this preview, we also need to define or a satisfied that on search click the parameters at the empty brackets and let's just build in a refresh to see how this preview will now look like our case. So there we go. As you can see, we have our first action inside our top bar. So there it is. It looks very nice and we're going to add up to more actions. So before we create the second action, a sort action, let me just put this string in our strings.XML. So let's open up our resource directory then as strings in here, I'm going to add another string and I'm going to paste this text. So search tasks are calleds close that and here let's call our stringer resource composable function. And let's pass here that ID. So R dot, string dot, search action. Okay, So here, if you don't see any import, you just need to go here and just paste this so the name of your package, then a dot r, Okay? And now that the error will be resolved perfect. So the next thing we need to create another action called the sort action. So let's create here a new composable function called the sort action. And this function will have a one parameter. So on sort clicked lambda and this lambda will actually have a priority. So was this one, so our priority, and it will return a unit. And before I continue with this salt action, there is one more component which we are going to create in order to use this sort action. So inside our roof package, Let's create a new package name. Their components are K and inside the set package, Let's create a new Kotlin file, and we're going to name this Kotlin file, our priority item, our case. So let's create here a new composable function, priority item. This function will take only one parameter and that is a priority. So our enum class, which we have already made and inside we're going to declare a one row with vertical alignment. So I'm and center vertically, okay? So incidence priority item or this row, we need to add the two components. So the first one will be a simple circle, which will represent a priority color, and the second component will be a text. So let's hear a user Canvas to actually draw a circle. Here I'm going to specify a modifier, some modifier, Android, the composers UI. So our modifier, I'm going to call here a size. So the size of this canvas should be a 16 dp. For now, let's import that. And this ONE draw lambda can be called in the body of this canvas because it's the last parameter in there canvas. So when we open up this canvas, you can see that the last parameter incidents function is onDraw lambda, okay? And when the last parameter of the function is the Lambda, then you can call that parameter in the body of that function. So just as we did right here, or game and incidents or draw scope, I'm going to draw a circle. So let's call here a function draw circle. And this function is only available in this drawer scope. And then here I'm going to pass a color for this, a circle. I'm going to type color, and then I'm g