Create a MVVM network image app with Jetpack Compose | Jitendra Pratap | Skillshare

Playback Speed


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

Create a MVVM network image app with Jetpack Compose

teacher avatar Jitendra Pratap

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

28 Lessons (4h 52m)
    • 1. Introduction

      7:34
    • 2. Installing Android Studio & set up emulator

      3:46
    • 3. Declaring minimum required dependencies

      7:24
    • 4. Creating Entity for room database

      10:33
    • 5. Creating DAO to access database

      9:06
    • 6. Adding Room Database

      3:29
    • 7. Introduction to dependency injection

      3:00
    • 8. Creating network module part-1

      18:19
    • 9. Network module part-2

      12:46
    • 10. Creating persistence module

      6:22
    • 11. Creating repository for data storage

      12:56
    • 12. Creating Repository module

      3:05
    • 13. Front End - Creating Home Screen Part -1

      20:21
    • 14. Creating Staggered Vertical Grid Home Screen Part2

      14:31
    • 15. Creating Home Screen Part-3

      13:29
    • 16. Adding main view model class

      13:09
    • 17. Adding Appbar & Tabs

      11:05
    • 18. Creating function for tabs & loading

      11:51
    • 19. Implementing Crossfade for bottom navigation

      21:40
    • 20. Creating Main Screen

      13:12
    • 21. Setting up Hilt & Dagger to make it hilt app

      13:52
    • 22. First launch & debugging errors

      6:47
    • 23. Fixing Staggered Vertical Grid

      2:41
    • 24. Creating list screen

      16:53
    • 25. Creating details repository & detail view model

      7:00
    • 26. Creating Image Details Screen

      15:23
    • 27. creating routes & navigation

      10:55
    • 28. Conclusion

      1:08
  • --
  • 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.

13

Students

--

Projects

About This Class

90dedbac.png

Learn Android app development with jetpack Compose and become a professional Android developer.

You can start as beginner and will become a Android Developer in no time.

Learn how to build a MVVM project.

Learn how to create Room Database ,LiveData, Lifecycles and ViewModels.

Learn how to use retrofilt and okhttp client with interceptors.

Learn Dependency injection with Dagger and Hilt.

Learn how to easily create list with Lazy Column.

Learn how to create Staggered Vertical Grid

Meet Your 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 guys and welcome to my course of jetpack compose, IMG tins, pick up your instructor. In this course. You have more than eight years of experience in software development and around five years of experience in Android application development. In this course, you will learn jetpack compose from scratch, and I will explain everything. So let's see what you will learn in this course. So in this course you will learn how to make an image repository app using Retrofit Room database and dagger hilt. We will use Material team to build the components. So this way, you will learn all the basic building block of compose. You will also learn how to create routes for navigation in jetpack compose. So in this course, we will use Retrofit library to make network API request using okay as TTP line from that to a repository. And we will use GET request to fetch the data from repository. You will also learn how to use coiled image to fit image from network and display it in the air. And along the way you will learn what is coroutines and flow and how and when to use them. Once we successfully get the data from the repository, we will inject the data in Room database using dependency injection. And once it is successful injected, the datetime to Room database, we will query the room data with using the DAO interface to get the data from room. So what the skills you need for these skills? So for this course, there is no particular requirement because I will explain everything. But if you have some basic knowledge of Portland, then it would be a bit easier for you to get all the concept. But even if you don't have experience with Kotlin, you can still enroll in this course as I will explain everything and unit enthusiasm because we are not doing anything new. It is just injected compose, and we do things a lot differently compared to XML based on Android app development to achieve the same goal, but it's quite efficient and time savings. Once you get your hands on jetpack compose, you can do app development on a much faster pace compared to XML best app development. So what tools are required for this course? So you need Windows 10 and y are the studio bumblebee canary 10. And you need a minimum of eight GB RAM if you want to run your app on emulator. If you don't have a GB RAM, then you can use your physical device because cannot be required a lot of resources to run the Android Studio and running emulator on a machine which does not have at least eight GB RAM, will most likely freeze your machine for a very long time. So I hope that you are very keen to learn jetpack compose at is it going to be the future of Android app development? So now I will demo the main app, which is the main project in this course. So it's an image repository app. It display a list of mountains and their name and hide. And the UI part in this home screen will be built using constant layout. And it's staggered vertical grid. We will use constant layout to constant these three components, which are images, its name, and height. And then we will use a staggered vertical grid to place all the images into column. And although I am using a staggered vertical grid, we will use the same column width or all images for consistency. And basically what happens in staggered vertical grid is you get multiple images of different heights. But for the sake of consistency of images, I will use same height and Column Width bar all images. So all images will align perfectly with each other, as you can see in this demonstration. So to get data from the network, we will use Retrofit library to met Network API repressed. So to get data from the network, we will use Retrofit library to make network API request using HTTP client and an interceptor from the app to an image repository which I have posted on get. The repository itself is not a proper rest API repository, but it's similar. It's like a rest API and meet all the requirements quite well for this project. And we will use GET request to fetch the data from the repository. Once we get the data from the repository, we will inject that data in Room database using dagger hint dependency using constructor injection in constructed index. And we define the list of required dependency by specifying them as a parameter to the class constructor, the class that needs the dependency must expose a public constructor that takes an instance of the required dependency as a constructor argument. And once it successfully inject the data into Room database, we will query the room database using the T0 interface to get the data from the room and display it in the air. So by saving all the datetime, the room database, your app don't have to make a network API request every time you open the app to get the data from the network. Because it already has all the data and it will make network request when there is an update in the repository. And so even if you're offline, you can use the app and can see all the data. Although the app make Network API request every time you open the app to see if there is an update in the repository. If there is no update in the repository, then it will simply load the data file locally from the room database. We will also create our nav bar to show the title of the app and a bottom navigation bar tab to switch between the two tabs that we have built. So this is the first step and this is the second tab. So in the second tab, we will build the list layout for same data using lazy list column to see all the images, name and height in a list view. And then we will build the detail screen to get the full size of the image and its detail. So if I click on this image or text or the height anywhere, we will go to the detail screen and here we can get full image of the mountain, the name, the height, and its description. We will use composable navigation to navigate within the app. And we will also create a little arrow to go back to the main screen. So if I click, we go back to the main screen, which I am the two of the home enlisted screen. And this one is home screen and this is lifted pin. Them both contain same data but in a different view. 2. Installing Android Studio & set up emulator: In this lecture, we will download the Android Studio. So if you have Android Studio, our text box, or later on your machine and your emulator is already set up, then you can skip this lecture. Otherwise you can continue watching this lecture. I am just going to download Android Studio from the official website. So here we need to say and write a studio bumblebee download. And it will take you to the preview link. So we can go to preview link. And here we have to build the bumblebee and the chipmunk. The bumblebee one is more well-tested. And this one is very lightly tested as it's written on the website itself. I have built a course on bumblebee, so I suggest you to download the bumblebee virgin. So I'm not going to download it because I have already downloaded it to save time. You can see it on my downloads. But all you need to do is to click on this link and accept the license dm here, and you click this link and the download will start. So it's started. But I don't need to download it because I have already downloaded it, so I'm just going to cancel it. Now after downloading the file, all you need to do is to extract the file and you will get a folder, a folder like this. So you can place this folder anywhere in Yoda drive. And basically this is installed version so you don't have to do much. You just need to go in this folder. And in the Android Studio folder. And inside this Android Studio folder, you need to go in the bin folder and you need to click this executable file, the studio 64. So I'm just going to click it now. And the Studio will open. So it has this started opening and it's going to take some time. So now the studio as it started, and the first thing we need to do is to create our emulator. Say on that top right corner, we have these three bullets. We can click on them and add. We have bunch of pins. So we can select the Virtual Device Manager to create new virtual devices. So as you can see, I already have three devices. To create a new one. You just need to hit this button. And here the phone is already selected so you don't have to change it. And from this list, you can select whichever specification you want to have it as emulator. So choose whichever you want and then click Next. And then you need to select the fifth term emit. So you will have to download one of these. I have already go to you on my system. So that's why it's not showing downloaded. But if you wants the mother, like pi or Q or R or S, You will have to download it and then select the system event and click Next. And here you just have to give it a name. Give whatever name you want to give it, and hit Finish. And your emulator will be ready. So that's it for this lecture. And I will see you in the next lecture. 3. Declaring minimum required dependencies: So after downloading the latest Android Studio, we need to create a new project. So lets clear did choose D and decompose activity. Click Next. And we can say image, repo, the toe, reach, up and back, getName. We can select whatever you want and choose the same location to the minimum SDK to API. It can reach to the maximum users and hit Finish. Now we need to define some basic dependencies for this project. So let's go to our project build.gradle file. And here we have extension for our composed. Well then, so this is the extension we are using, though it's been used here in our app level gradle module. Here we are using the compose worsen, but this is not enough and we need more dependencies. So the first thing we need is the gradient tool. So let's define a Gradle build tool. And while the number is going to be the end point, the point 0. Now we need to declare the Android plug-in per Gradle. So to declare the plugin, we need to create a dependency block. So we can write dependencies. And it appears the past. We can do this one. No, not this one, sorry. Dependencies. And in this block we are going to define the Gradle plugin. So to define, we can say class path and remove the curly braces, small braces, semi-colon com dot, android dot. Tools build. And here we can select Gradle. So instead of her directly using the extension number, we can define extension here in this one. And then we can pass it here by providing a dollar sign. And then we can say, great Del Valle tools. So if we need to use the same agenda again, we can just use these next ten Chen. So we will not be confused if you accidentally use some other number. So just for that, you can create extensions here in extension block, and it will be easier to use these extensions. So after we need to define what I've done for Portland, so we can define an extension again. And Cortland equals and this one is going to be 1.5.10. And then again, we need to define the plug-in for Kotlin as well. So we can take class path for RG dot brands, dark Kotlin, dash, Gradle. And we also need to Dahshur provide plugin. So we can say dash plug-in and then we can pass the extension for Kotlin. So dollar sign and Kotlin. So now we need to define the repositories for our project. So today find repositories, we can say repositories. And there are two repositories basically that we use. So those are Google and Maven Central. So we can just declare it here. Now we need to define the plugins for bottling kept and Kotlin Android app level, gradle file. So we need to switch to build out griddle. And here we can define the plugins. So to define plugins we can say ID, Kotlin, bash kept, and Kotlin and bright we can say ID and or D, jetbrains, dot, dot o. We already have, Actually, I did not see that, but we already have the plugin for Kotlin and bright, so we don't need to define it. So let's same p times z if we get everything right. And we have a failure here. So seems like we missed something. So it's a classpath could not find or JetBrains Kotlin. So let's see what went wrong here. So this is where the problem is. So themes like we are work to provide the balloon naming convention. So that's why it's showing up. So here we can say, just forget to write the Kotlin. And I think now we will be fine. So let's run it again. And this time it says, we were able to successfully think our project. 4. Creating Entity for room database: Now we need to create a data class. But the app where we can is stored the variables for our data. So for that, we need some dependencies or Room database. So the room isn't O RM object relational mapper. For SQLite database in Android, it's a part of architecture component. It to make using SQLite much easier for you by implementing and notations. So you must be wondering why we cannot use the SQLite directly. Well, actually you can use this fill light directly, but it has its flaws. And the biggest drawback of using SQLite database that it leaves that it only throws runtime exception, which means that if you have any error in your query, it won't detect on compile time. You will only know about it when you actually run there. And by that time, you might have right, a lot of queries or a very big query. And it can become very difficult to identify the error because it does not give you any syntax error. So you will have to manually check it every line by yourself. However, with Room database, you can identify that f in your query at compile time and can prevent the app from a runtime exception. So there are three main components in the room database. The database itself, entity and DAO, which stands for database access objects through which we access the database. So this is a little slide to understand the room database. So this is the entity that we are going to create in this lecture. So an entity basically hold the field values. And then we're going to have a data access objects, which is an interface which is used for accessing the database where we will create our functions or you can call it queries. And then when we can use those queries to exit the room database. So let's create then 31st. But to create an entity, we need to define or declare the room database dependencies. So let's create our room dependencies first. So we'll, we'll go to the project with Gradle file. And here we need to define the Virgin for room. So room. But gen equals to my Num Lock is off. So 2.3, let sync it. Now we need to define the dependencies for room in our app level gradle file. So I can type here room. And the first one is going to be the end bright room time. And so I can say implementation. Remove the small breadth is and dried x, dark room, colon room, free room. And then we can set dash, run time. And instead of passing the room were Jan, per every dependency, we have just created a room virgin in our extension blog. So we can pass that room margin. Now we need the dependencies war room itself. So we can say implementation and ry dx. And we can choose the first one, AndroidX room, room CAPX. And again, we can remove the Virgin number air and can pass the declared room Virgin. And the last one is going to be the room compiler. So instead of implementation, we will use captain. So capped and ride x. And we can choose the room compiler. Now we are done with the dependencies for room. So let think now. Now we can define our data class. So let's define it by going here. Image repository app. Right-click, click on New Kotlin class. We can say here image select class which is already selected. And to make it a data glass, we just need to prefix it with data. And it's an entity, so we have to annotate it with an entity. Now we knew the field values, what our data class. So we can take our liberate is now we need another dependencies for compose runtime. So let's quickly declare the runtime. So we can say EHR implementation, AndroidX.com, Dart runtime, and then colon run time. Here we can pass the compiled version of Soviet need to provide the dollar sign. And let's keep listen kick. Now in the data class we need to define the primary key bus. So to define the primary key, we can say the primary key. And for some reason, it's not detecting the primary key. So let's try again. Maybe we need to rebuild the project because sometimes it does not work is straight away. So let's rebuild it. So to do that, we can go to bed. And first we clean the project by clean project. And then we can rebuild the project. And by using the build project tab, it's going to take some time. So I have now rebuild the project and let's see if the IP severed to detect the primary key and notation. So we will slowly type eg primary key and this time it has now detected. So sometimes it happens in this Android Studio that it's unable to detect the dependency straight away. So you can always go to buried and they clean your project and rebuild project. And it will detect the dependency again. So let's declare our primary key. So we can say val ID. And it's going to be of type. Long. After that we need a title, parabola f. We can say title. And it's going to be of type string. And after that, we need another four image URL. So we can say image URL, which is also going to be of type string. And the last thing is going to be the height of the mountain. So we can say at IIE THT height, also typeof It's string. Now we need to and notate this data class emitter at immutable. So we will say that immutable, which requires the composer and time. Without this dependency, we cannot use the same notation. So the ad immutable and notation is the promise that all public accessible properties and peel value will not change after the instance is created, constructed. So what we are trying to establish here is that value that we have defined a at id title the image URL and I should be the same from the repository. We are, we are trying to access the data. They should match. The repository is filled with ALU should also match with this data class. Otherwise, we won't be able to fetch any data. So this is a very stronger promise that the value cannot be changed even with the getter and setter function. So as long as you don't have getter and setter methods in this data class, you can use this notation. Otherwise you should not use this notation. So I hope that clears up with the active metabolite mutation. And we can format this code will to control. I'll you, pick two, would look nice. 5. Creating DAO to access database: Now that we have created our data class for time to create the DAO interface for all the queries so we can access the database. So we need to create a package name persistence. So let's clear the packet. We call it persistence. And then we need to create an interface for image DAO. So we can say knew, you knew what link class. And here we can select the interface and we can name it image, the EO. And to make it a DAO, we have to notate it with the ad PAO. And now it's an interface. Now we can create our SQL queries inside this interface. So the first query is going to be an insert query. So we can send a spend function insert image, list. And we need to pass a parameter. So here we are going to pass the images. We can say images Poland, and it's going to be our four type list. And here we need to pass our entity class. But we can say the ment, choose the image class that you have created. Now we need to end notate it with the MNO act insert n notation. Here we can add, Insert. And now we need to provide a strategy for images with the same primary key. So suppose if you have an image with an ID one and you change or update the image in the repository. But in that you have the older image for that ID. And when you open that, the BIO Bill find that that there has been updated image with ID1. So what it should do in that case. So in this case, we can provide a strategy to replace the old image with the new one. So to do that, we can say, as it already suggests S In this in certain notation, you can use the on conflict method. So we can say on conflict. And here we can say on conflict strategy. And here we can say dot replace. So what it will do, it will replace the older image with the new one part, the same primary key. So that's how you manage the conflict between the old data values and new values for same brand leaky. Now we need a function to fetch single image. So we can say function get image. And here we need to provide an ID. We pause every image, have a primary key. So we can say id dash and which is going to be of type long. We will have to provide the Taiping also. And here we are. We'd need the live data. And I guess we have not. Yeah, actually we have. So we live data. And here we can pass the entity, our entity, so we can pass the imaging to t. But sooner or later we are going to need the lifecycle live data dependency. So let's declare it anyway. So let's go to the project to build gradle. And here we can say live by Google, virgin, which is going to be 2.2. Now. Now let us define the lifecycle live data dependency in AP level build. So we can say lifecycle live data. And here we can say implementation and write x dot lifecycle. Well, we can choose the live site, but we'll live gotta k dx. And we can provide the Virgin number air. So at Nortel, add a dollar sign and lifecycle virgin, and let it sink. Now. And let's get it back to our DAO. So now we need to provide them notation for the query. So we can say at query because it send query. So we can say that query and air inside the small braces we can say as trach wrong and air, we need to pass the entity class. So we can say meant where ID equals and we need to pass the colon ID. And it's already showing there the variable we created here. So this is the function or query to select a single image from the repository. Now we need another function or query to fetch all of the images from the repository. So we can again, they're spend function, Get, get the images. Let say get the image list. That would be better. And here it's going to be of type list because it's a list of images and not a single list, an error we should provide our image entity. And again, we need to annotate it with that query because it's a query, Slack query. And here we can select as strength wrong image. And I get that checked. So you must be thinking what is suspend function and why I use it in these two queries and not in this one. The thing is that when you do big calculation process, you don't want to do it on the main thread because it can take a long time to fetch all the data as if we are trying to insert or load with this function. So the first friend functions allow us to do this task in background on a separate thread. So even if it takes a long time, people won't reach the F. And we'll run this node. And in this query, we are facing a single image. So we can use just the function because the one single image is not going to take a very long time. So here, we don't need to use a suspend function. 6. Adding Room Database : Now the last thing related to the room database is the database itself. So let's create a class for the room database in the persistent package. So new Kotlin class, we can call it database. We need to make it abstract. Because Room provides an abstraction layer over SQLite database to allow blue end database access while harnessing the full power of SQLite and room, we'll have the database object to Java objects. Now, we need to extend this class with Room database. So here we can say Poland room, the database. Now we need to call our V0 into this abstract class. So we can say abstract function image. The WHO extended by image DAO. We will have to make this function abstract because the room database, this class itself is abstract art abstract class. An abstract class cannot have non abstract function. Now we need to end notate this class with ADD database and notation. So add database. And we need to provide some parameters in this notation. So the first parameter will be entities. Entities, and we can provide it in brackets. So we have only one entity in our project. So we can say Image and colon, colon plus. And the next parameter we need to provide is the version. So we can say Virgin. And it's going to be one because we have not created a database yet. So it's always start with one. And the last parameter we need is the export is schema, which have the true value by default. But we don't want to export this schema, so I can say false. So basically a schema contains the information about the structure of your database, along with the history of your database virgins and entities, and the queries in a JSON format. So if you want to have the schema, then you can set it to true. Otherwise, you can set it false. So this is the end of this section in which we have set up the room database. In the next section, we will set up our network module with the help of a dagger. And that profit. 7. Introduction to dependency injection: In this section, we will be building our d i and network module. So we will start with D, which is a Stanford dependency injection. And as we required the components from network part d, we will build the network components in between. So let's understand the dependency injection. So in app development, classes often requires reference to other classes. For example, a car class might dependent on in class. So this class becomes dependency. But this car, because car plasma is dependent on class, engine and need and in stance of engine class to run. Third, there are two ways for a class to get an object that it needs. The car class can construct the dependency it needs like this. So we have a class car and it has a created his own in stands for engine. And have, we have a function to start the engine. And then in the main function, we are calling the instance of car, starting the car. So this can be problematic as far and in general, tightly coupled. And you cannot use an alternative implementation for this car. If you want to have a different engine for this car, you would have to create a different class or car to have a different engine. So this is when we do without independence in Jackson are other ways that the class can get the dependency as a parameter. So that can provide these dependency when the class is constructed. Or you can pass them into the function, that new DG dependency. So in this example that our constructor would receive in Jen has a parameter. So in this approach, you take the dependency of a class and provide them rather than having the class instance up-tempo themself. In this approach, the app creates an instance of a class and use it to construct an instance of car class. And then didn't classes a Petri defined which make the connections between these two classes loosely-coupled. So this is the best approach and it encourages reusability of car class. So you can pass in different implementations of rent-a-car. So that was the ultimate introduction to dependency injection. 8. Creating network module part-1: So let's build our network model with dagger and lt. So we need dependencies of dagger and held. So we need to define the hilt core version and introversion index 10, ten block. So let's go to the project level build. And here we can define our margin. Core virgin. So going to be 2.37. Then filter by region 1. Now lead the class path for the Democrat and plug-in. So we can say dot, google.com, dagger, colon, dash, Android, Gradle plugin. And we can pass the hilt code virgin head, legs. And good. Now we need to define the plugin ID in app level gradle. So we need to go to A1. And in the plugin section, ID dagger dot dot, android dot plugin. And now we can declare our dependencies for decorate. Here. I will say dagger Harold. And the first dependency is going to be implementation dot Google, dot the dagger, Poland, L, dash and dried colon. Held poor virgin. The second one is going to be the dagger held compiler. But we can say Captain. Well, dot-dot-dot, dagger, colon, dash, compiler. Colon held core Virgin. And the third one is going to be held compiler for Android X. So we can save Cat and write x.com left and we can pass the hill to Virginia. Now we can think it. Now, we need to create a package for DIE. So we can go ahead and select that click new packet. We can call it d. In this package, we need to create a network object. So we can say new Berlin class and air. We need to select the Object because we are creating a halo object here. So we can say network. So we need to use it as an object of any state of class to make singleton. So it can have only one instance and it provides a go global point of access to the object. It is useful for objects which need to be shared between different parts in the app, and for resources that are expensive to create. Now we need to annotate with at more doable. So we can say that module. Then we need to and not dealt with at installing. So we can say that install. And for some reason it's not detecting than notation. So we can rebuild it by cleaning the project and they will ignore it. So we can get the dependency, the n notation. So let's see if it works. So now after rebuilding, we get this error saying that installing and rotation is missing. So let's see if the Android Studio is able to detect the installing and notation. We can say that installing and this term now it's able to detect them notation. And to make it a singleton component, we can say in return component colon, colon. It basically tells him to generate the components. Otherwise, you will not recognize this object. Now we need to create an HTTP client to send HTTP request and response. So inside this object, we can say button or TTP, blind. And it needs a parameter. So it neat application context. But we can say that application context. We need to provide the context with App application context. And then we can say on text, on text. Now we need to add the dependency for the PICC line. So let's get back to the project level, been liberated L. And here I can say, okay, as TTP, then I can say or 0.7.2. And I can think now, now I can define the dependency in the middle layer. I can say, okay, http, line and air. I can say implementation com. But it's quiet. Dark. As TTP three. Poland, Poland logging in Bash Intelsat per colon. And then we can pass the margin bottom http. Now we can think. Now we can get back to our network module. And we need to extend this function with our okay, HTTP client. So we can say, okay, and inside this function we need a builder, borrow HTTP, client, and acceptor and utility to serve the response cache. So we can use it to build the response. So we can say, we're done. Okay, HTTP client. Now we need the one, return, HTTP client, buildup and dot add interceptor. Here we need a request interceptor class to add, remove, or transform the headers on request or response. So the HTTP headers let the client and server pass additional information with an HTTP request or response. So let's create the request interceptor class in network packet. So we need to create a new package, package network. And here we can direct our interceptor, the request intercepted. So we can say request enter that. We need to extend this class with the interceptor. So extended with intern habitat. In this class, we need to override the interceptor function so we can press Control O. And we need to override this function intercept. Air. Chen is an interface that returns the connection on which the request will be executed. So now we need to chain our original request. So we can say, we can remove this to-do and we can say Val or original request equal chain dot request. We need to chain this request to decide whether the data is compressed and then checksum or check sum and then compressed, okay, or TPUs list to track interceptors. So they can be called in the right order. So after this, we need to build this request. So we can say, well, the request, the request dot a new builder dot URL. And we need to pass the original request to a URL. So we can say original request URL. And finally then we can say maybe, then we can return this request by saying return chain dot, proceed. And we can pass the request. This chain dot-product is a critical part of interceptor implementation. This method is where all the HTTP works happen. It produces a response to satisfy the request. So let's get back to our network module and pass this request interceptor to our interceptor. So we can say bequest interceptor. We need to select this one, the one we created. Then we need to provide a method to set the response cache. So it can be used to raise the response. So we can say at partner dot cache, Something's wrong here. We also need to put the small braces here because it's a class. Then we can say dot cache. Now we need the image loading library, which can fetch and Display Network image using coil. So we need to add another dependency bar coil. So let's get back to our project level, build gradle. And here we can say foil virgin 1.3.5. And let's sync it. Then let's get back to the app level Belgrade L. Here I can say cuboidal image and then implementation. And here I can say bom dot, github dot died of colon, land escapist, dash, then colon. And then we can pass that. Now we can think now. Now we can go back to our module. We can say things like we did a little mistake with the adding the dependency. So let us get back to the app gradle file. And I think there is a typo. So I think yes. And let it sink it again and let's see if we get dried. So let us try to use it again. Coil utils. Now we get it. But there was a typo mistake. So we can say coin you tills, not create default cache. And we need to pass the context here. So we can say upon text. Here we are trying to optimize the cash-in stands for coil. Because by default, every image loader is set up for discussion. And we'll certa max cache size of between ten to 250 MPI, depending on the remaining space on the user device. So this function will create an HTTP disk cache with a reasonable default size and location. And finally, we need to call the baby. So dot build. Now we need to end notate this function with AD provides. So we can say, we can say add provides. So that held can throw null pointer exception in case of an exceptions because by default it'll does not allow null values. And then we have to add notate with ADD single tone and notation to prevent it from creating multiple in stance. 9. Network module part-2: So after okay, HTTP client, we need a function body image loading. So let's create it. Function image loaded. And it required some parameters. So it requires the application context. We can say application context and then context, context. And it also requires though HTTP client. So we can say, okay, HTTP client. And then we need to extend it with the image loader. So we can say Image Loader. We need to use the point of origin. So the image loader is a service class that loads the images and by executing image request. So they are designed to be shareable and best when you create a testing well in stance and share it throughout your f. So we will have to annotate with that provides and singleton. So let's do that. Now let's build the image builder. So inside the function we can say return image loader dot, very large. And here we need to pass the context. Are provided the context, the context. Then we need to call the HTTP client. And we need to provide the client in curly braces. So okay, HTTP client. And then we need to call it. So that's it for image loader. Now we need to create a function to provide retrofit. So for that, we need dependency or retrofit. So let us get back to our project period model. And in the extension block, we can say retrofit virgin T equals 2.9. Let think now. And then getting back to app level gradle. Here we can say vector affect, implementation. Com dot square up, dark Retrofit to colon, retrofit colon. And here we can pass the retrofit virgin. But I profit margin. Then we need another dependency or JSON converter. So we can say implementation on the square up to colon, dash d, so on. And then we can pass that at profit margin. So let it sink. Now. Now we need a network response interface for handling successful data and Arab response. So let's declare the dependency for it also. So f, We can pay sandwich. Well then, which is 1.2. Let's sync now. Let's declare that dependency for it. So we can say implementation dot GitHub, dark sky down. For Lean Sandwich, colon. We can pass that sandwich were then. Let's sync it. Again back to our network module. Now let's clear the function for providing retrofit. So we can say function that profit. And it takes, it will cast you to PICC lines as a parameter. So we can say, okay, HTTP client. Let's extend it with retrofit. And chimps likes it sooner, not detecting the profit. So we can do the same thing again. We can claim and rebuild where we have rebuild this again. And let's see this time, if we can get it, detect the retrofit dependency. Now we get it. So I don't know why it's happening quite a lot lately, but it does not have been where you offend. So let's get it on with it. But profit. And then we need to NO2 it with ADP provide and at single tone that provide at singleton. Now we need to create the Retrofit builder inside this function. So we can say return retrofit dot builder. And then we can say dot client. We need to provide the client. So we can say, okay, HTTP client. Then we need to provide the base URL. So the base URL from where we will provide that data for this app. So I will quickly show the repository for the app. So this is the link where I have created a small repository of mountains with their height and description and image URL. So I will put this link in that resource so you can get it from there. And what we need is we need to click this rock. And it will take the taking to this link. So we have to copy this link. And we have to copy until this point. So we have to copy all the liquid link until this point and put it on our base URL here. So we can say baseURL from where we will fetch the data. After that, we need to provide the converter. So we can say ADD converter factory. And we're going to use the JSON converter. So a JSON converter factory create. So we need JSON for Sierra Lij sent to and from JSON. Then we need to call the adapter factory for supporting service method return types. Then call. So we can say Add, call it up perfect tree. And here we need to pass coded coroutines response, call it up perfect tree. So we can say or routine response call that a perfect tree, dot create. Then we finally called the build method. So dot. Now we need to create an interface for image service where we can set an endpoint and then API response. So we need to create a package for it. So we will say new packet and we can call it network. Next up is already IPO. We have already created the network package. I forgot, sorry. So here we need to create the interface for image service so we can send new Kotlin class and we need to select the interface. And I can call it Image Service. So inside this interface we create a suspend function. So spend function. And we can call it retrieve image list. And we need to extend it with the API response. So I can say API response. And we need to provide the list of images that we can say list and pass our image model class. There is a typo mistake, so I can now we need to and notate this function will get. So we can say Add, get, and we need to provide the end point for it. So the end point will be this link. At the end of this link we have this Image.all JSON. So this is the endpoint or the service, so we can copy it and paste it here. Now we need to use this interface in NetworkX module to provide the image service through retrofit. So we can go back to our network module. And here we can say shun, provide image service. And it required retrofit as the parameter that we can set our profit. Then we need to extend the image service that we created. So remember service. Inside this function, we can clear the service by saying return, retrofit dot, create. The main image surveys, Poland, Poland class dot Java. So that's it for the network model. And next, we will build the persistent module. 10. Creating persistence module: Now we need to create a persistent modules so hidden it can communicate with Room database because we want to save the data in local storage. So the app will not have to fetch data from network every time you open that up, once I hit Save in the database, it will be loaded from room determinants. So let's create the persistent module. So new. We can call it persistence. And to the upset and notated with the module. Then we need to annotate it with the at installing. And it requires some parameters. So in well component Poland, Poland class. We need to specify this requirement to make this object available in the application container. Now we need to provide an instance of image. Do. So, let us say a fun. Provide the image, the AO, and it requires a parameter of our database. So we can say Add database, app database, and then we need to extend it with our image DO so we can say Image DO. Then inside this function, we can say return app database, dot image, DAO. And here I have a little typo again, so I need to correct it. So in this code tells him that database dot image do needs to be executed when providing an instance of image DO. So, then we need to enter to it. With that provides. Though we can say that provides with the ADP provides it will be Q debt every time Hilton needs to provide an instance of that type. Then we also need to annotate with a single tone to make it single tone. Since the project does not own its own database, because it's generated by a room. So we cannot constructed inject app database, but we can use at provide functions to provide it. You will get to know constructing, inject in upcoming section when we'll, we'll create main repository. So let's create the function provide App1 database. So here we can say function provide database. And it requires a parameter of type application. So we can say application. And then we need to extend it with the app database database. Inside this function, we need to create the room database builder. So we can say return the room dot database builder. And here we need to provide some parameters. So the first parameter is it is a application. Then the second one is what I am database that we can say AB database, Poland, Poland class dot Java. And then it needed the name for the database. So we can get it from the string file is strings.xml. So we can say application, but the gap is string. And we can say R dot, string, dot. Okay, we need to import the resource. So r to plus Enter. And now here I can say database, which we don't have created yet. So let's create date. So create a string value resource database. And we can call it image dot baby. Let's save it. Now, we need to call our next method dot, all back to this destructive migration. So you can call this method to recreate the database whenever you change the schema. So instead of crashing, it would recreate the whole database again. And then finally, we need to call the build method. So then again, we need to annotate it with AT provides and single term. So this is our persistent object. 11. Creating repository for data storage: So now we need to create the repository module. And for that we need to create a main repository class where we can define how and when we should call the API request and what should the Abdu in different scenarios. So let's create the packet. We can call it repository. Let's call it main repository class. Here we will use the constructor in Jackson party mixed service and image DO. So, we can say at inject and it required constructor. So we can say constructor. Inside this constructor, we define our variables for image service and image DO. So we can save Private, well emit surveys than private well, emit the 0. So by declaring these dependencies, we inject some constructor. It guarantees that this dependency will always be available to the class that we are currently developing. And by requiring all the colors to supply the dependency as a parameter to the class constructor. So when a class require an, an instance of path dependency, you can supply that dependency through the class constructor and it enables it to store the difference for future use. Constructor injection is the act of statically defining the list of required dependency by specifying them as a parameters to the class constructor and the constructor signature available for all to see. Now we need to initialize it so we can say in it. And here we can just love it. So we can say log D and error. I can say image repo repository. And I can say just a message repository. We need to import the log. After that, we need a function to load images. So we can say function load images. And it needs to be annotated with the work-up threat. So we can say at worker thread. So we're cut threats are background threads. They are the trips that are created separately other than the main UI thread. And we should not run this function on men thread since it's a service and not attached to an activity or fragment. Since blocking the UI thread is restricted according to the rules and the user should run the child processes and tasks in workup threads. Now we need to create three methods. For honor start on success on error. So in the constructor, we can say on the start. So going to be of type unit, unit means it does not return anything. Then on success. Again going to be unit type. And then we need on era. So we can say on error. And it takes a string as a parameter because it's going to be a method. Now we need dependencies or poor routines because we need to pour routines flow. So let's declare the routine dependency. So we can go to the project module blade. I can say. Hello being larger than 1.4.1. Then in the app level build gradient, we can declare the CTO Dan dependency. So here I can say implementation or reject brands. Kleenex, Kleenex, dash, dash, colon. And then we can pass the origin Coroutine version. Now we can think of it. Now we can use flow. So flow is the type that can emit multiple values sequentially, as opposed to a suspend function that returns only a single value. For example, you can use a flow to receive life of deaths from our database, which is what we want to achieve it. So here we can send equals low. And now we need to provide the flow collector. So here we can say val images, which is type of list. Then we need to provide our image model, the type class. Then we can call our getting med list from image DO. But we can say Image DO, dot, get image list. Now we need an if else statement to check whether we have images in database or not. So we can say if images and we can check it by saying is empty, then we will request API network call, RAM image service. So here we can say if the database is empty, we can say Image Service, dark but retrieved image list. Then we need to handle API response for success, error and exception. So we can say dark, spend on success. And here we can say emit, DO dot, insert, image list. And we need to provide the data for it so we can save data. Then we need to call the init function with the data as parameter. So we can emit and provide the parameter data. Then for error, we can, we need to set the API response. So we can say dot on arab. And here we can just to separate the method after on era, we need to set the response by exception. So here we can say on pepsin and we will pass the same message. Then in the else part, which is right here. If the database is already loaded, then we can just emit or images. Then we need to call on start function. So here we can say onStart and we can pass down and start to function a there. Then here we can say that on completion and we can pass down fat cells method that we created earlier. We can pass the function and then we can call flow on. So we can say dot blow on dispatchers. Dot io. We need this flow operator to change the context where this flow is executed. The given context, because by default, the producer of global debt execute in the coroutine contact of the core routine that collects from it. And it cannot emit values from a from a different code looping construct. This behavior might be undesirable in some cases because the repository layer should not be performing operations under this paychecks dot Min. So to change the Rubin construct of a flow, we use this intermediate operator flow on. So looks like we are then here for the main repository class. And this error message, this error function has not being used. Themes like we have left something. Okay? Okay, so we need to pass this on error, function error or an exception and not just dumb method. So we can say on ARAF with the message. And yeah, we are done for this main repository class. So next thing we're going to build the repository module. 12. Creating Repository module: Now we can create repository module. So in DIE, we create our repository model object. We can say repo, DO RE. And we need to select the object. In this repository module, we just need to provide the function part a man repository. But before that we need to annotate it with that module. And then we need to annotate it with installing. And we need to provide V-model component, colon, colon plus. So the ViewModel component as the lifetime of a single ViewModel. This Herald component is the source of a hill to view model. It contains default binding part the same state handle associated with the ViewModel that can be used by their dependency provided by the component. So dependencies in the ViewModel component can be scoped. Using the ViewModel is Spoke and notation, which we are just going to use. So here we can say function, provide main repository. And we need to provide the image DO and image service as the constructor. So we can say Image Service, image service, and then image DO, DO. And then we need to extend dict with our main repository that we created in the previous section. And then we can just call it the return function four main repository. And we need to provide these two parameters. So we can say Image Service and the image below. And we need to annotate it with ADP provides. So we can say that provides and then add the view model is booked. And we are done part of the repository module. So this is it part of the back-end part. And from next section we will be working on our front-end. So I will see you in the next, uh, Chen. 13. Front End - Creating Home Screen Part -1: So from this section onwards we will be building our front-end. But before that, I need to do some correction because in the last section I made a mistake. Air on era. There. I need to pile on error function and not just the message, but I can say on era. And we need to pass this message and the woman's. And now we can move on with our front-end. So the first thing we will build is the home screen in which we will so all the mountains images with their name and height in a staggered vertical. Great. So let's create a package for screens. There I can say new package is screens. And in this package, we need to create a Kotlin class, not class file. So I can say home screen. So the first thing we will create is the composable function to display a single image. Then we will create another function to pass this function in the staggered vertical grid. So let's start with at composable, where we can save pan function display image. And it's going to need some parameter. So the first thing is, will be the image itself. Then we can say image. It should have important, but it did not import the image from my packet. And second is we need a function to select the image that we can say the elect image, which is going to be of type long. Then we need a modifier. Modifier, modifier equals modifier. So we, I think it is the first time you are seeing the modifier. So we use modifier to decorate or add behavior to compose UI elements. For example, if we want to set a background or viewer padding to image, then we will have to use modifier. So inside this function, we need to have a set of pace. So let's say startup pace. And we need to remove the import here. So sorry, sir, phase is the central metaphor in check pet compose. It influence how a piece of surface we actually relate to other surface. And it also responsible for clipping and shaping and providing colors and adding border and setting elevations and most importantly, and link click events. So we can say inside this small braces, we can see a modifier, equal modifier, dot padding. We want some padding around the surface. So we can say 4 dot dp. And we need to import the DP, so r plus. Then we want to have a clickable effect on the image. So we can say that the clickable non case one, but this one. And inside this clickable function, we can provide the onClick function. And in this onclick function, we can pass our image function. And we can provide the ID per image. So we can use this image variable to serve the ID. So we can say image dot ID. So now we are done with modifier. And now we can check the surface properties after modifier. So let me see. So here we can say Palma. Color. And we can pay a material themes, colors, dark background to set the background color. And then we can send the elevation. So for elevation we can say elevation equal GBP. And then we can also provide a shape for our surface. So we can say share equals and we can say a bounded coordinates tape. And here again, we need to provide the DP. So it will be 8.8 BP. After defining surface, we can define the extreme component. And for that, we need to use constraint layout. So we will be needing the dependency for constraint layout. So let's add the dependency. So in the project level and build gradle file, we can say Add Trend layout, where Ajahn and which is 1, dash 07. And then we need to sync that project. Now we can declare the dependency in the app level build-up Gradle. So here I can say on screen layout. So many typos. Anyway, this is not necessary. So here we can say implementation AndroidX dot constraint layout. And I guess we can select the constraint layout compose. And we just need to pass the Virgin on standard layout virgin. And we can think now, now in here we will define the constraint layout. So we can say constraint layout. And here we need to create references. So what are dy dt and that we are going to have in the screen in the spring. So there are three items that we will have. So we will have three UI items in the constant layout. And those are the image itself can fit image pig. And I am using a different variable name because I have already used the image variable m. So image pick and that can the element will be tied down. So we can say title. And the last element will be height. So we can say i. And then we can say create the friends. So that's how we create referencing constraint layout in their pet compose. After this, we need a function to display the image from one network. So now we need a custom network image function. So let's create this function so we can fit the image from network. So we will create a new package, and we will call it u tilde. And here we need to create the network function. So we can say network image. Here we will start with that composable. Then we can fill function network image. And this require some parameter. So the first parameter will be a URL incentives. Hence it is fetched from network, from Internet URL of type string. And then we need a content if stale content to scale. Because we need to crop the image so we can say and turn the scale about crop. Then we will be needing the modifier. So you can save modifier, modifier, impulse, modifier. And after that, we can certain that while image library. So we can say while image. And we need to choose this one, image, the model. So again, I need to remove this Import. Sometimes it import all the text on the function itself and also here. So you can remove it always if you get it here also. So it made the model for image model. We can say URL. And after that, we need to provide shimmer parent, parents. So we can say shimmer params. And we need to provide a color for it so we can say base color. And then we can say material theme. But Pelops, dark background. And we also need the highlight color, so we can say highlight color. And for this, we need to create a new color so that we can highlight. So we can go to our UI package. And here in colors pile, we can copy this value and paste it. And we can say it. Cima highlight. And we can choose a color from here. So we can click it. And I want to have, I guess this pillar around here. And after that we can get back to our networking match. And for highlight color, we can say xihuan highlight. And what else? We also need a modifier. So we can say modifier, a couple modifier. And we also need the drop-off. So we can say drop-off. So it's going to be 0.6.5. So it can adjust the size of the leading edge of the highlight. And after modifier, we can set the response in case of failure per image request. So we can fit a layer and we can use their text air. So we can say text. And we can provide the text here. So we can say image, request buried. And you can provide a style for the text. So you can say style. Material, theme, dot typographic. Eye for graph P is used for styling text. There are a number of options. You can select whichever you want. I'm going with the body to the other SAR, very big actually. So be careful there. And yeah, I guess we are done for the networking met. So we can get back to home is three. And here now we can call our network image. So network image. So far URL, we can pass the image dot image URL. And we also need the modifier. So we can say that modifier, modifier. And now we need to constrain the image to a. We can say dot on strengths as. And we need to pass the friends that we created this one. So we need to pad the image picker difference there. Then we have to provide the scope for it. So we can say, then horizontally tune and we can say parent. And then we need to link the top to the top of the parent. So we can say top dot, link to buy or rent dot top. And since it's a mix, so we need to provide a spectra ratio for it. So here we can say dot aspect ratio and I can say 0.8 F. So after image, we need to create the constant or the title. So here we can say tech. And for text we can use the image dot title. Then we can provide some nice styling. So we can say it's tile. Again, we are going with the material thing, the typographic body two. And then we can align it to centre so we can set the text line and text aligned penta. And then we need to constraint it. So we can say modifier, equal, modifier and dotted bond strain as we can say title. Then we need to provide the scope for it. So we can say then there has been cleaved to parent to make it, to make it in center of horizontal. And then we need to link to the bottom of the image. So we can say and link to and we can say Image pig. So now this time we are going to link it to the bottom of the image so we can say Image P dot bottom. And here we need to provide the topic Chile. So top to the link of Image button. And then we need to do the same thing with the height. So we can just copy and paste down here. And for text we can say metadata. And for constraint we can provide the height pair. We can say top dot link to titled dot-dot-dot. And we also need some padding. Part of both of these texts. Though here I can say padding of ADP. And for this one, we can, we need to set both horizontal and bottom padding. So how does one tell a dot dp per bottom? We can hear, we can say dot padding bottom. And we can provide 12 dot db. So that shaped the single image. Displacing the limit. Display MIT 14. Creating Staggered Vertical Grid Home Screen Part2 : So after creating function to display a single image, now, we need to create a composable function to display the list of images. So we can say here at composable function, display images. And here we need a list of images. So instead of just image, we can say list. And then we can provide the image data class here. Yeah, After that, we needed the function to select the image. It can remain the same as display image. And then we need the modifier. So we can say modifier, modifier and then we can initialize with the modifier. Now, we need a column where we can put our Display Image function in a staggered vertical grid. So let's define our column. So basically, a column is a composable layout in which you can put your UI elements in our tuple sequence, like you do in XML with LinearLayout having vertical orientations. Now we need to initialize the modifier. So we can say modify it, equal, modify it, modify it. And now we need to have scrolling behavior because it's a list of images. So it can be very law. So we need this is calling functionality. So we can say modifier equal, modifier dot, dot, vertical scroll. And then we can use the function, a composable function, which is called a remember is scrolling instead. Remember it's grown instead of scrolling. So what it does it that it creates this state. And remember the position based on the currently scroll configuration to allow changing scroll position. And it also observe the scrolling behavior. After that, we can set background color. So we can say, yeah, here, dot background and we can use Material Theme, pellets, dark background. Now we need to create a stagger vertical grid where we can display all images in this column is called so far that we need to create another function. So we can go to our util package and say New Kotlin class and we need to choose file. And we can say if staggered vertical grid. So here we can say at composable function, staggered Vertical rate. And it's going to required some parameters. So the first parameter we need is a max column width. So we can provide a column width. So we can say max column weight. And which is type of dp. So we can select that dp of AndroidX.com dot dot unit. Then we need a, okay, we need to import the DPS as well. So we can say our placenta. After that, we need the current dead inside the grid. So we can say content, which is going to be of type composable. So we can say at composable, provide the unit, and then we need the modifier as well. So we can say modifier, modifier, modifier. Then we need the layout function, which is used to measure. And then pudgy send multiple layout children. So we can say layout and content. We can set the content we just created. So we can set it to make the content. And we don't need the major policy. But we can remove this. And we need to modify it. So we can say modifier. And we can do the same with modifier. So we can set the modifier to modify it. Now we need to check the bounds of the weight. So we can say Miserables trend. We need the Lambda function. And then here we can say check on screen as bounded width. And then we just need to, then we need to set the message here just in case off in finite weight. So we can say unbounded will not support that. So what it does, it, it will return true if it has a finite value for the max width. Otherwise, it will return files and it won't create integrate. So once it has changed the max width, we can then define the Children's. So now we can define column for the grid. So we can say we need to define the column first. So we can say value columns. So we can say value columns. And we can again the column number of column by dividing the max-width with the next column width. So we can fake costs 10 dot max width. So we will get the max width of the screen. And then we can divide it by the value that we will later provide with this max column width. So we can say max column width. Then we need to create it to pixel. So here we can just say start px where it will clear to the pixel. And then we need this column to be a whole integer value. Because this calculation will definitely give float value because the max fit, sorry, it has to be mapped to wit my bag. So the max width can be vary depending on the screen side. So we can convert into it by saying to the end of this curly brace, we can say dot to end. So we can get the value in the rounded number. Then we need to define the width of the column. So we can say value column. And here we can take constraints, constraints dot max weight. And then we can divide it by the number of columns to get the column width. So it will get the width of the column. And then we need to provide constant for the items that we are, that we will be put in the grid. So they all will be same way as we said them. So we can say value item bond strength equal on strain dot p. And here we will set the max with two column width. So all the items in the grid or in the column will have same way. So it will be only as big as column width and won't be as wide as parent of this green. Otherwise, it could take the whole is pin and you won't see the second column next to, we need to define the height of the column. So we can build value. Column height. And this is going to be of type int array, integer array. And we need to provide the columns. And we need to set the initial value to 0. So we can initialize it with Internet with initial value of 0. And we can pass columns as a parameter to keep track of columns. And then we can later decide the height of the column. As we put the items in the column. Like when we put in the, likely when we put items in the column, it will measure how much height it needs, and then it will provide the energy for the column. Then we need all the items that we are going to put in the column. So we can say value pleasurable equal. Make the rebels dot map. Here we need a miserable. Then lambda function. Then we need to define which column is shortest, shortest. So we can put the next column be needed. Of course, in our app, all the image will be almost same height. So we can say value column equal shortest column. And we need to provide the column heads, sorry, column heights. So this function we will need to create it. We will just create it shortly. But the Latin finish this vertical grid first. So now we need to measure all the decibels. So we can say where you place a double equals measurables dark Mazur item constraint. And then after measuring the item, we need to add the height of that item to the column height. So the column I can increase as we add more and more item. So we can say column height. And the column as an array because it's an integer array. And then increase the height from the height that we get from the play symbol. So here we need to pass the columns. And then we can get by saying plus equal Play Symbol, dark height. Then we can return the play symbol. So we can say, place the bell. 15. Creating Home Screen Part-3: Now let's make the function or the tower test column, where we can say a private function, shortest column. And it's going to require a parameters which is colon height. So we can say Orland heights, which is of course subtype integer add a. And it's going to be of type int. Here we need to define a variable or a minimum height. So we can feel variable min height. And we can set it to Maxwell loose so we can say int dot max value. And then for the initial lights artist column, we can initialize with 0. So we can say where alum equal 0. Now we need to measure the height for each indexed. So we can say alum HIV AIDS dot for each index. And it requires the indexed and I am going to change it to hide. And here we will just use an if statement to check the height. So we can say if it is smaller than min-height, minimum height, then we said the min-height, minimum height to hide. So we can say min-height equal height. And then we said that index to the column. So we can pick column index and then we return the column. So here we can get done column. So that was the function force to find the shortest column. Now, get to back to the staggered vertical. Great, because This function is still required some work. So after replaceable, we need to get the largest column from all the columns we have. So we can say where Lu, ICT and equal Golan Heights dot max on null pair we are trying to see. So it will return the largest element or null in the case. If there is no element, then we have to check the height. Then we need to check the height that live between to make sure that tick lies between minimum height and maximum height. So it should not be less than minimum height or more than max height. So we can use the course in function to concentrate in. So we can say dot or in. And here we need to provide the constant or minimum height and maximum IOT as well. So we can say constant dot max, height. And here we need to provide the question mark, which I forgot. And let's get to the second line. And we also need, we also need to set it to the minimum height. So if we cannot satisfy both of these are constant, then we can set it to minimum height. So we can say Denmark dot on sprain. Why it's not taking. Maybe I should put it all of them in one line and see what happens. So here, I can fit question mark, colon, constant, dot, min-height. It's too big anyway for one line. Now, we need to provide the scope for the layout. So we can say layout. And it required two parameters. So and we can set it to constrain the width and height. So we will set it to the height that we just calculated above. Now we need a column for JSON for a y-axis. So we can place them at position life 000, which is the highest point on the screen. So we can say value along y, equal and array. And we need to provide the columns here. We can say columns and we can initialize would be 0 because we need to start from 0. So we can, we will initialize with 0. Now we need to go through each item we want to place. So we can say place the bell dark or each and air. We need the play symbol followed by lambda expression. Now we, now we can put this artist column based the value of column y. So we can say value column equal star test column. And here we can just provide column lying. Then we need to place it on the screen so we can say plus double dot place. So we need to start from 0. So we can say x t equal weight into column, which will give the position of 0 at x axis. And then for y we can say column y. And we can just provide the column here as area. So it will give the position for the first item and the top left corner on the screen. And it will add the height of that item onto the y-axis. So when we will put the third item, it will start from that position and not from the 0, 0 position. So next we need to add to the column y of the height of the previous items. So we can say column y. And we need to provide the column so it can keep track of the column. And then we can add the height so we can replace the burn out height. So that's it for the staggered vertical. Great. Let me see if we get everything right. I think I have missed something because this column is not the getting used somewhere. I have made a mistake or sure. Also we need to make this measurable and not Miserables. Okay, Are we need to pass the shortest column, this column, and the column that we defined, we can say Harlem. And we are good part of this. The staggered vertical grid. And it's not easy to get it first go though. If you don't understand it completely at first, then don't get panic or disappointment. You will get it by going through the court couple of times. So I tried to read and analyze if you don't understand it, and then it will become more clear and you will understand it better. So now I want to stagger vertical grid in our home screen. So let's do that. Who we are, we can tag and vertical grid. And it required the max column width, as I mentioned when I was making the vertical grid. So we will provide the max column width in home is green here, and it will divide the max width so we can get the number of columns. Here. I can say 225 dot-dot-dot ATP. You can choose whatever you want, between 200 to 250. And then we need some paddings around. So we can say a modifier, modifier padding of four VB. So it will get the pirating of four dp from all sides. Then we can then now for each collection on the image variable. So we can create a param for single image and then loop that display message function through lambda expression. So we can say images dot bar each. And here we need to provide a image variable and then lambda expression. And here we can pass our Display Image function and image body image. We can set the image, this image variable that we just created. And four, select Image B can pass the Select Image function. And I think we are good for the home screen. I'm getting this error. So let's see what is that function is staggered vertical grid. I just did. So we are getting some errors and it is something to do with the staggered over to Google. Great. So let's go back to the grade, our food, our grid. And here I made some mistakes. So here we need the ceiling to actually converted to NTC. I forgot that one. And I think we need to provide this modifier plus 10 before anything else. That is the reason I think it's not working, so let's do that. And yeah, now it's working. So that's it for the home screen. And in the next section we will be building our view model. 16. Adding main view model class : So in this section we will create our view model. So what is ViewModel? We use the ViewModel class to store and manage UI related data in a lifecycle conscious way. The ViewModel class allows data to survive. The device configuration changes that chess is screamed rotations and tends to keyboard availability. Also in view model, we convert an apse ui.R to encapsulated live data and add observer methods that time notified when the value of LiveData changes. So this will model will be associated with the main is clean, which will create afterwards. So let's first create a packet or a menu screen. So packet, we can see him in green. And here was our ViewModel. So we can say class men view model. We need to annotate with at hilt view model because it's L DAP. If it was not filter, we will just annotate with we model. Then we need to extend this class to ViewModel, so we can say View model. Then we need to inject the main repository within Jackson constructor. So we can say classmen V-model at inject constructor. And we need to import the injection. Let's define our main repository. So we can say private Val value, men repository, main repository. Now we need to declare some mutable LiveData, which requires lifecycle live data dependency, which I think we have already declared. Let me check it. So life-cycle live data we need yeah, we declared it from time ago. So we are good to go. So let's create our past mutable LiveData, which is an image list. So we can tip private Val. And that is core image list, mutable LiveData. And it's going to be of type Boolean. Boolean. Then initialize mutable LiveData, add the value to true. So mutable LiveData exit class and it extends the live data data type class it to provide the most value set value methods publicly. Something that live data class does not provide. Live data or a mutable LiveData is commonly used in updating data in a recycler view or in our case, lazy column ROM collection of lists type. Lazy column is the new RecyclerView in jetpack compose. And it is much easier and sophisticated compared to RecyclerView, also very easy to implement. So next variable we need is downloading variable. So we can say private. Where are we going with that? I worked Val, we can say under this code is loading. Also going to be of type mutable LiveData. We can say of type Boolean. And then initial value, we can set it to files. So this is loading variable will tell that whether the data is there a loading or not. So when it's loading, it will be true. And when it's not loading, it will be files, though. Initially it will be set to false. Then we need a variable for the toast message so that we can show error message and response. So we can send private value or Val. And that is both doest, which is also going to be mutable LiveData. But the typing will be string because it's mostly a message. Also need to initialize it with just a mutable LiveData. Now we need an observer to observe the changes in the image list. So we can use LiveData, which is a data holder class that can be observed within a given lifecycle. So we can say value image list of type live data. And here we need to provide our data class. So fast when you provide, provide the typing lift. Then we provide our data class, which is image. And then we can set it to the value. We created a air image list. And we can say dot pitch, map, switch map returns the live data from the input of this LiveData by applying transform on each value set on this, which we are just going to create. So we can say this dot main repository dot load image. Then we will have to provide all the functions that we created in the main repository as a parameter to load image. So in a load image parameter we can say on start and onStart, we can say, we can set this loading to true, so we can say dot post value true. Then we can say on success. And we can set the loading variable to false. So we can say if the loading dock post 12 noon false. And then we need the earth. So we can say on Earth and on error we will just provide a toast value. We can say Toast dot post value, and we can just say it. So onStart we can say is loading is true. On success. We can make it to fall so we can stop the loading. And on adder, we can post the toast message by providing it. Because the error message sat already declared in main repository. Afterwards, we can call the calculation as the LiveData function. On this, we can say dot as live data. And it requires a whole routine context. Because co-routine context include a coroutine dispatcher to determine what trait or threads that corresponding code or 10 uses for its execution. Because co-routine always execute in some context represented by your value of the coroutine contexts type. So let's create the coroutine context. So for that we need an extension for this. So ViewModel. So let's create the ViewModel extension. So where should we create the extension? Let's create a new package for extensions. Extensions. And we can call it vw Modelica extension. And we don't need class. We can just fair value. Viewmodel. Viewmodel i o context of type co-routine context. And now we need to call inline function to obtain the dispatcher to our coroutine context. So we can say inline get. And we can say our ViewModel is co routine context plus dispatcher. Dispatchers dot input-output. So we inline function to reduce runtime overhead because in Kotlin, all higher-order functions are stored as an object. So memory allocation or both functions, objects and classes and virtual calls might introduce runtime overhead. So inline keyword request the compiler to not allocate memory and simply copy the inline code of that function and the calling place. And then we append the dispatch dot io input output, which is optimized to perform this coordinate to work. Input-output outside of the main thread. Because this load image function is running on a worker thread, as you remember, and not on the main thread, and which requires optimizations. Now we provide this view model input, output context as a parameter to our live data function in our main view model. So here we can say ViewModel input-output context. Now, we also need an observer for our toast. So we can say a value of type LiveData, provide the string. And we can say get. And we can set it to tote. So get function is used to set a getter, like we were doing POJO classes. So that's it for the ViewModel. And we will add more items as we require then as we build our f. So the next thing is we are going to build out a screen where we will create the main is clean. 17. Adding Appbar & Tabs: So after creating ViewModel, now, we need to use the ViewModel to set our screens. So let's clear the screen function in the screen package where we will unload all our repository data. So in the screens, create a new Kotlin file. Let's call it the screens. So before we build our screen, we need to first create an MBA. So let's clear the bar fast. So we can say add composable function. Here. We can bring the top bar from material design. So we can say top bar. And we can give some properties to it. So we can say elevation dot dp. And we can give it a background color. We can say background color, purple to 100. Let's bring it down to the second line. And let's give it a height. So we can say a modifier equal modifier dot height. And let's give it 45 dB height. Then we need to provide a text for it. So let's say text. And for tax to me, we'll use the string resource to get the name of the app. So we can say our text equal a string resource. And here we need to provide the ID for it so we can say ID, string, name. And I guess I have to import the resource, otherwise they cannot access it. So let's import did and R dot, string dot. We can be happening. Then we can provide color for it. So we can say color, equal color. So color dot. And we can give some font size. So we can say font size 18 dot ASP. And then we need to import the SPF Val. And then we can give some font-weight. So font-weight, we can say a font-weight, bold. And let us give some padding. So we can say modifier equals modifier, dark padding, padding of ADP when we can say dot HTTP. And then we can align it to centre vertically. So we can say alignment, dark center vertically. So that's our AB bar. Now we need to clear that taps or a bottom navigation. We are going to have two tabs. So we need an enum class to create constants or the two tabs. And each tab have a title and an icon. So let's create an enum class. So in class, we can say Image tab. And we need to provide the two parameters per title. And I can. So we can say air. So we will use the titles from the string resource file because we should not hard-coded string variables. So to declare a string resource variable, we can say add a string resource or the string Val. We can say title of type int, because we have already declared it as a string resource. And in string resource, all the string resource have their unique ID. So we fetch them using the ID and not the string. And this is something Android Studio does under the ODE and take care of it by itself. For icons, we can simply declare them as imagery octet. So we can say, well, I can type a message vector. Now we need to define the two tabs here, which are separated by a comma. So we can say on and we will fetch from the source file. So we can say R-dot the string dot the same menu underscore home. And we have not created it, so we need to create this resource. So let's just create it. We can say it home. And then we need an icon for it. So we can say icons dot, dot on, which already comes with two jetpack compose, but we don't have to direct our own icon. And then we will have another depth per listed screen. So we can say lift. And here we can say R dot string.me. And that is core lift. And let's clear this one as well. So we can call it list. And we can use the icons for it. So I can't start period dot list. Now we need to create a companion object to certain the call for toe taps. So we can call the tabs without creating an instance of this class. And also you can accent it's numbered using only the class name as the qualifier. So let's do that. Campanian object. And here we can save function. Again ten apps from the source. And then we need to provide the two parameters. No, not doom, but just one resource. So we can say that the string type resource variable named resource type end. And then we have to extend it with the image tab. We just created a. Then we can return the when function to switch between the two tabs. This when function is conditional expression with multiple branches. Here we have only two further tabs. So we can say return van. And we can pass the resource in the as a condition so we can save and resources or resource. And then we can say R dot string.me list. So if it's a menu list, then we will call the list. And otherwise we can use the else statement. So we can say else. So this way we have setting the Home tab as a default tab. And the when function match, matches its argument against all branches sequentially until some brands can be sending satisfied. Okay, everyone needs to have what is called semicolon. Semicolon. So that's it for this section and we will keep building. This is gaining the next section. 18. Creating function for tabs & loading: Now we will create the function for the screens in which we will put the top bar and the bottom navigation, where we will have the tabs and the data related to the respective taps. So let's denote the function is creams. So here we can say that composable function, the screens. And it's the need two parameters, the view model and the function part selecting image. So we can say View Model. And we can extend it to men ViewModel that recreated. And the function for selecting image, we can select image, which is obviously going to be of type belong, followed by unit. Then we need a variable for emit. So we can observe what's going on in the repository. So we can say value images. And we need the list type part, the images per our data class images. So let's get the data class. And then we can say by ViewModel. So we VR using the serif friends view model to get the image list from our view model. But we can save you model.py image list. So let me just open our view model. So here we are trying to get this function in to the screens. So we can say by ViewModel dotting medalist. And then we can call the observed as a state. So serve as dot, observe as data. And I cannot find this. The function looks like I'm missing on our dependency, so I will have to check it. So let's go back to our build out degradable. So we have AndroidX compose runtime. Let's see, we have runtime for reliable data. And check here. No, we don't have the runtime for live data, so we need a dependency for a onetime live data. So let's it 382. I think we should put it with the runtime composer. At runtime, I think I should put it here. So we can say implementation AndroidX, docker, compose, Dart runtime. And we can select the runtime live data. We can get rid of the Virgin number and provide the compose version. And let's think now. And when we should be good for using the state observer as a state. So now the thing is complete and let see if we can use it. So we can say dot observe. Now we can find it. So observe as a state. And it can provide the list that we can say list off. And we need to import then dr.com post.rb untimed. So we can just import it. So what it does, it, it does start observing this live data and represent its value. We stared. And now every time there would be a new way Lu posted into the live data, the return is stared will be updated and it will cause recomposition of every state. So next to we need a function for selecting the tab from the bottom navigation. And for that we need to go back to our main view model to create the variable or selecting tab. So let's get to our main view model. And Ed, we need to create a variable to select tab. So we can say private Val and their scores. So I can add. Here we need a new table instead. So we can say Lu table is state. So the new table is 30 is the new table value holder. And if they read the value of this property, they were in the execution of this composable function. And it's needed to be of type int. And then we can initialize it with mutable is tear it off. So we can say new table is taped off. And we can initialize it with 0. It returns a new mutable initialized value with the new path didn't value that we provide when we switches the tab. And it's a single value holder class, which means it can only have one value at any given time, which is what we want to achieve air. Then we need a state interface to save this value. So we can say value select tab of time is state. And then we can pass the end. And then we can use, we also need to import this state. So just to use import the AndroidX.com dot runtime. And then we need to serve the getter. So we can say get. And then we can set it to select tab. Then we need to create a function to select the tab, where we can say function selected tab. And there we need to provide the string resource. So we can fare to string resource tab of type integer. And then we can update the value from AIR. So we can say, and that is called select tab, dot value equal tab. And we need to add notated with the main thread. So it will run on main thread. So we can say that men thread. And as you know, the main thread is a UI thread, as we discussed in the previous section. But it's very small function to switch between tabs. We can run it on men rate. Now, let's go back to the screen. And here we can create the value for selecting the tab where we can say value. The lag equal. We can say Image tab dot, get tabs from resource. And here we can pass our view model. Select tab dot value. Then we need a value for loading to show the surplus circular progress indicator when the app loads that data. So again, in the main view model, we already have the mutable LiveData. We just need to real the live data is loading. So let's here create the value for loading. So we can say value is the loading of type. Livedata is going to be of type Boolean because its side that loading or not loading. Then we need another good time to get the value and then set it to. And that is good if loading the mutable LiveData. And we can get back to the screen again. And here we can say value is loading equal Boolean. We can save by Boolean, by ViewModel. We should stay small. By v1 dot dot is loading. And we can, we need the observed by the standard error as well. And air, we can set the initial state into balls. Okay, here we need to use the colon and the equal sign. So in next section we will create a constraint layout to put together the body and progress bar part. This is screams function. 19. Implementing Crossfade for bottom navigation: So let us create the constraint layout to put the body and progress of this screams bile together. So we can say class parent layout. And again, by now you must know that we need to create representatives for the constraint layout. So we can say value. And we need a body and progress. Well, we can set body and progress. And then we can say create reference. Now the first thing we need is to put the bar on top of our screens. So for that we need is scaffold. And if scaffold implements the basic material design visual layout is structure. And it provides API to put together several material components to construct your screen. And in zeros. But layout is strategy. But then, and it also collect the necessary data. So these components will work together correctly. So things like App Bot Auto floating action button, or a bottom navigation, not a good example to put together under the scaffold. So let's just do that. Though. We can say is scaffold. And to go into some parameters that we can say background color, material, theme, dark colors, primary surface. And then we can say top bar. And here we just need to provide them Barbie created. So we can say bar. And that's it, but we need to constrain it. So we can say modify it equals modifier dot on strengths. As an add, we need to pass the first difference, but we can take body. Then we need to provide this code. So we can say a little bit SS, and we can say top link to parent dot. After this, we needed the bottom bar so far that we need another dependent thing for the bottom bar, paddings and hide and provide windows sets with CI will you see later. So it's called accompanist, insets and dependency. You can find more information in link, which is given in the resource. So let's declare the dependency. So we go to the project build. And here we can say what Ajahn and air, we can declare the origin, so 0.10. And we can think now here I miss the M typo mistake. So let's do it again. And then to build a very dull and we need to declare the dependency. So I can say then if inserts and air, we can say implementation com dot google.com. Then again, accompanist, dash in sets. And then we can provide the version number or an accompanist. And why does n? And let's think now. Now we can declare the bottom bar. So we can say we needs to be indented the scaffold. So here we can say bottom bar, and inside this bottom bar, we can say bottom navigation. And it needs some parameter as well. So we can say background color. We will set it to purple to 100. And then we need a modifier to serve the navigation bars height. So we can say modify it equal modifier dot navigation bars height. And to set this navigation bar side, we need the inserts. So it's coming from a company's inserts. Without it, we cannot set the navigation bar height. Let's do that to 56 dot-dot-dot. And then we need to provide the row is scope or this bottom navigation because we have a toe taps and they will put together in a row. So we need to declare a type variable passed. So on top of laughter is loading. We can say value tabs. And we can get that from our image tags. So we can say image tabs dot value. And now we can use it. So wherever via bottom bar, bottom navigation. So now we can run a for each lab on these tabs, where we can say tabs dot forEach. And we can create a variable air tab. Then we can call it by lambda expression. And here we can save bottom navigation item. So what top navigation item? Not a bottom navigation, but bottom navigation navigation item. And it has some parameters. So it's Material Design, bottom navigation item. It is recommended configuration for a bar and bottom navigation item depends on how many items there are inside a bottom navigation. It provides all the necessary functionality for a bottom navigation. So to sell FOR selected, we can say Tab equals double equals selected tab, select tab, the left tab IT AND created a select tab. This should be actually selected tab. So let's rename it. So it will, it makes more sense. So we can refactor it the refracting. So now we have selected tab and the bar on click. We can just say we can remove the to-do and we can say View Model tab. And we can provide the tire tell. So we can say tap, F dot title. Let's move it to the, our next line so it will look easily. We can look at easily. And then we saw Neil the icon. So here we can say icon and far icon. We can just pass the icon type image back to the image vector. And here we can just say dot icon. And for content description we can just pass null. You can pass a string a few. One does not really matter. Then we need level also. We can fill label. And for level we can simply pass our text here, but we can set tags. And again, we will be pulling the text from the string resource. So we can say string resource and which needs an ID. So we can say that dot title. And we need a color. So I can say color, the color to white. And here we have some problem with the pillar. Actually, we don't have problems in propeller. We have problem when the ID actually, yeah. It should be. I forget to Chile. Get out from the small breadth. And after label, we need butler for selected content. So we can say that elected content color part of the selected tab. So we can say local content pillar about current. And we also need a color for unselected content means unselected tab. We can set it to saying, if you want, you can set it to something else. It's your choice. And we need the paddings to apply a definetly space. We match the height of the navigation bar side along with the bottom edge of the content. And additionally, space with two matches the width of the navigation bars on the respective left and right edges. So we can say modifier equals modifier, dark, navigation bars Berlin. And we'll just apply by itself. So this is where the you scaffold components complaint. Let me check it again. Yeah. Here it is complete. And now we need to declare the inner buildings so we can fill the screen with the image and the details. Here we can enter adding followed by lambda, expression and air. We need the cross-fade. So CrossFit allow us to switch between two layouts with Rothbard animation. So we can say grass-fed and it's required, our target is third, but we can say the electronic tab. And then we need to provide the destinations so we can switch between them. We need to create a destination fast or destination variable. And now we need to provide the Lambda expression. Then we can run the van conditional expression. So we can say Ben, the destination and the air. We can just say image tab.com. So if we are on home, we can switch to display images. And we just need to provide the images so we can get rid of this equal. And we again get rid of this equal as well. And then we need another destination for list. So we can say and lift image, which we have not created yet. So let's just created quickly. We won't put anything in this file yet. It can just say list image. For the sake of the project. Let's call it actually list is green naught image. So we can rename it. Let's screen and air. We will just say list is cream. And it's okay, we don't have anything inside this list is cream for that's why it's not getting it. So let me quickly put something inside it. So what we can put it, we can just put this composable function. Here. We can put these composable function. We can get rid of this parameter and air. We can simply say immense left tab. And we can call the greeting function at Chilling. So after, after inner padding, we can declare the surplus progress indicator. So very end. It turns here. So after inner padding, we can say surplus, circular progress indicator. And here we can provide some parameters for it. So we can say modifier, equal modifier. And we need to constrain it. So we can say dot on standard says we can provide the progress. And then we need to provide the constant is caught. So we can say top link to dot-dot-dot. We want this indicator to be in the middle of the screen. So we will have two constraint it from all sides. Now we can say bottom, willing to rent botton, then we will have to link it from the start. So we can start to link to start. And then from an outside we can send that link to buy or rent. And so in this way, it will show in the middle of the screen vertically and horizontally. Now we need an extension of the visibility off, sorry, polar progress indicator. So let's clear the extension. So in our extension files, we can say new modifier extension. And we need to create a function to further visibility. So we can say function modifier, visible and air. We need a parameter for visibility. So we can say with the builder of type Boolean. And it needs to be extended by modifier. And in this function, we will return the value of color. So we can say if visibility. So we will say this darker than one. Else. We can say this the dark The than 0 f. Okay, We need to annotate it with that this table. And here we need to provide the Alpha. So inside this alpha, we can pass this one f. And here we also need to provide the alpha and pass the 0 f. So depending on the value of 0 is loading, it will change the Alpha, so it will be seen or disappear. The sparkler, a progress indicator. So back to the screens. We can now hear say Dart, miserable and we can bug is loading. So that's it for this section. And from next section, we will be building our main screen. 20. Creating Main Screen: In this section, we will set up our main screen in order to be able to run the app. Because we have built quite a lot in this app, but have not run the app once. So we need a couple of things, mode before we can run this app. So we need to create routes and nav controller to navigate in that. So let create these things in main screen. So we will create our main screen air many skin packet. So let's create a new file and call it main is green. So in this main screen, we need to create a seal class per route. So we will say fail the class. Nav is Vin, and we need a better route. So we can say, well, route of type string. Then we need to create an object per home route. So we can say object of type nav is green. And we can hear that out here by thing on. The sale class is an abstract class with restricted class hierarchy. So it will only be, only can be accessed through this main screen. Only this main screen can access this field class objects because it's defined inside it. Inside this class. This provides more control over the inheritance. And they are restricted, but also allow freedom in state representation. And the seal class cannot be extended by any other class. Now we need to build the navigation in the main screen function. And for that we need dependency for both Android X and navigate. And here's navigation. So let's go to project level build file. Okay, we made a typo so we can connected by putting the columns. So let's go to the project level, British Belgrade L. And here we need to define the word gentle loads navigation. So first of all, we knew that that composer navigation. So we can say compose navigation. And the Virgin is going to be 2.4 dash 09. And then we needed the navigation. So we can say 1.01 dash alpha or three. And here we need another row. And we can think now. Now we can declare dependencies in the app level gradle file. So here I will say navigation. And let 30 find AndroidX navigation past. We can say implementation and dried x dot navigation, colon navigation compose. And we can pass one. Then we can say navigation, Compose, Compose navigation. And then the hillock navigation, we can say implementation and dry. And we can choose the navigation component. And then we can pass the margin for the head navigation actually. So, yeah, this one. And we can think of it. Now back to main screen. And now we can create our main function. The screen function. So we can say composable men screen. Here we need to create an app controller past that we can say value nav controller. And we can use nav controller you to create a controller that handles dialing up, composing navigator and dialogue Navigator. Then we needed to create a local context. So we can say value on texts. And we can set it to local context, not absolute, local contexts dot current. Then we need to apply window in value to the local window insets to hear insects mean size. Window inserts are in sets of system view, like top m bar is scattered about navigation bar that are applied to the window so that they can be applied in proper layer. Otherwise, there could overlap on each other or the AB bar and the navigation could go into background layer and you weren't able to touch them. So Window and make sure that every component is in its proper layer and not messing with some other component layer. And it's provided by Google, a company's 10 sets, which we declared in the previous section. So we can provide window in fact. Then we need to create a NAT host here. So we can say nav most. And it requires the nav controller. So we can pass our nav controller value, which we created. So we can say nav controller. And we don't need the graph. And I have a graph, we need a destination, we need a star destination. So we can say start destination. And we can set it to Navi screen.com dot route. And then we can provide the nav graph builder. So in this nav graph will let me create that out through composable function. So we can say composable and air, we can pass that out. So narrow screen.com dot route. Here we need to create the nav back stack in tree. And for that we need to reference to our main view model. So we can say, well New View Model equal heritage view model. And here we need to provide the main view model. So we can say men will model. Then we can set our streams. So we can say add screens. And it need two parameters, ViewModel. So we can pass our ViewModel here. And for the selected image, we can just leave it as it is because we have not created the detail is clean yet. So we cannot go to detail the screen. So we will leave it here. After that, we need the toast in case of API response failure. So we can say View Model about Toast, dot observe. And here we need to provide a Lifecycle. Lifecycle or not. We can pay local lifecycle owner dot the current. And then we can create our toast. But we can say Toast, dot domain, dot, txt and air. We need to provide the context. But we can save context. We can pass the context here, then the message. So the message can simply be eight. So we can pass the eight and then we need to pass the length of their duration. For the toast. We can save those dot length. And then we can finally call the show method function. So dot show. And then we can create a log, so we can logcat the ADA as well. So we will just say log e. And here we can, we need to import that tag. So let's import the content to be able to tag. And here we can see many screen and we can pass the eight. We can say plus 8 dot to string. And yeah, that fit or manage pain for now. And that's all go hotter this section. But let me also do a quick fix in the main view model because I made a mistake. I did not make the mistake. I just forget to initialize the view model. So here I just need to initialize it so I can say in it. And let's lock the file as well. So we can say love B. And I want to get rid of DAG, and I just want to provide the message. So I can say View Model. And then here I can say View Model initialized. So that's it for this section. And in the next section, we will set up this menu screen into the main activity. And then we will find tune the project to run on them later. 21. Setting up Hilt & Dagger to make it hilt app: So now we will bring this main screen to our main activity file, which provides the entry point for the application. So let's go to the main activity. So here we first need to create a separate class to inject our image loader function, which we created in the network model. If you remember, in our network module, we have this image loader function. So now we need this email order to fetch images from the network. So we can use it head in MainActivity. So let's create the class. So let's get rid of this boiler plate code. And we also need to get rid of this greeting. And here we can say plus root view model and inject constructor. Here we can initialize the image loader. So we can say Eval Image Loader. And you can see that we have a little icon there. And if we click it, it will take to the network module. So it's saying that we are now refreshing this function, this held function in our main activity. So after that, we need to extend this class with two ViewModel. So we can say for Lenin view model. And inside this class we just need to initialize this class. So we can say in it. And we can log it though, we can say log b. And we need to import that tag. Just import it. And in message we can just say initialize root view model. So we need this image loader function to support, to provide the support for loading images from network. And now we have to end notate this class with adhered to view model also, we can say, okay, it will model. Now we need a reference of this route. We model in the main activity. So here we can say value View Model of type root view model. And we can say bye. I think we knew that this one. Yeah. And we all have to notate it with the with the bell for deserting. We can say it with the ball for testing. So what it does it to relax the visibility for this field so that it is more widely visible. Otherwise, we will have to make it private. And he'll just does not work with private variables. Now, we need to correct this entire piece of code so we can curtail it. And we need to put it into composition local provider. We can say I'm position composition local provider. And we need to put all this the code inside the function. So composition local provider, what it does, it, it binds well to provide the bulk composition local keys. And it reads the composition local using composition local dot current. And it will return the value provided in composition local provided so value parameter, but all composable functions that are Karg directly or indirectly in this content. So now we need to provide the coil image loader in this composition local provider. So we can, we can remove these values and air, we can say local image loader. And we can pay provides. And head, we will just pass our image loader. So we can say in May the Lord ViewModel dot image loader. And then we need to provide and notation for this main negative t. So here it can note that this file is the entry point of this f. So we can just here at Android entry point. Now we need to make this AB. Ab. So for that we need to create a class with same name as the name of this project. So the name of this project is image repository. So let, let's create a class. And we can say knew what Lynn class. And we can say image repo, Dory app. And we just need to expand it with the application. And we need to add notate with hearing ten Roy dab. Now we need to go to manifest pile to provide some additional information about the app. So we can close all of these screens. And we can go to manifest file. Here. We need to provide the permission for the Internet using, so we can say you that permission. And there we just got the file permission about Internet. So we can use it, declared it. And then we need to provide the application name in the application blob. Here we can say android name and as it solidly detected the name of the app. So we can say image repository app, the class we created just earlier. This one, it will work as the name of the app. Now when you do the base class component activity, or activities that enables composition of higher level components. So after the activity tech, then here, we declared the component activity. So we can say activity and we have to provide the name. So we can say Android X dot.com tech diversity. Then we need the provider for the startup. And part of that we need to, we need a startup dependency. So we can go to Project build again. And there I can say if star equal 1, my Num Lock resolve. We can say 1. And we can inhibit. Then in the level buried, we can declare the dependency. So here we can say startup and then implementation. And Android X dot is. And we can choose the startup runtime, this one. And then we can provide the version number for it. So we can say a startup. And then we can think again. So the app is startup library provides a straightforward performant way to initialized components AT application startup. It is used to streamline the startup sequences and explicitly said the ardor of initialization. It also allows you to define components initialized answer that share a single content provider. And this can significantly improve at startup time. So let's declare it in manifest file. So after component activity, we can say provider. And the first thing we need is the authorities. So we can just need to use our startup. So we can say we need to provide the package name so I can say com dot py orbital peaks and then the name of that. So we can say many depository app. And then we can provide the AndroidX startup. We can send dried x dash. Start up. Then we named the name so we can provide them with startup dot, the initialization, provide that. And then we need to provide a couple of more parameters so we can set and dried ported. We need to make it false. So it just indicate whether this application component is available to other applications. So it is a stand alone application and does not need to communicate with other application. So we can say false. And then we need the tools node. So we can share tools dot naught equals. We can provide the mortgage or remove. Both will work. And why it's giving the red light. Okay, I need to import it. So r plus import our placenta import. So this attribute ensures that the manifesto merger tool properly results any conflict. Conflict entries 0 in KSR. If we have multiple manifest file, I mean the epoque can only have one manifest file, but then by the studio, can, may contain several manifest file provided by them in solar cells, build variants and imported files. So in that case, if there is a conflict, conflict, so what do we want to do? So we can either mark it or remove it. So the market is the optimal solution. So we should use March, so that's it. And I think we shouldn't be running the app. So let, let's try and run the app and see if we can get returning. So I'm going to append my emulator. And just I will start this one. So then we'll return is up and I'm just going to click Play button to run the half and see how long it takes to run the app. And I have tried to run the app and we ran into some problems, actually a lot of problems. So we will fix all of these problems in the next section. So do not worry. We will get all of them. So I will see you in the next section. 22. First launch & debugging errors: So this is where we end up in the last section when the Arabs, though, before we move on and pinpoint that has passed, we need to add a plugin bar Kotlin Android, which I should have done much earlier, but for some reason I forget it. So we need to go to the app level, gradle. And here we need to add the plug-in for Kotlin and right. So we can say DID. And then Kotlin dash and dry it. And then we can sync it. So let's sing now. So what we've, what was the problem? Actually? The problem was in the Build Log, but since we syndicate, the log is gone. So I have to run it again to see the problem. So let's do it again. So now we have got the problem and let's see what it is saying. So saying that dagger missing binding and it saying that for image service network dot image surveys, we are missing the bindings for dagger. So let's go there and see. So we can just click here on this class and it should take to the Senate per class. And it did not take us to that class object. So we can go by our self there. So I am going to close this and Let's go to our network module. So NetworkX module. And here it's saying that we have problem with image service. So let's go to the image surveys and this is where the problem is. So here I hear, I forget to add notated with that provides and at a single tone. So we need to do that. So let's do it. So here we can get provides. And then at the end. And let's run it again and see what happens. So after rectifying that problem, we don't have any build problem. But same slide here. We still have some problem because the sparingly sewing blank though, we are not getting the images. So we need to work on those. Also, we have forget to use the inner padding in the screens file and the content. The scale is the never used. So we need to use it otherwise the image cannot be scaled. So I think that is the problem that the images are not loading. So let's go to the network image. And then the content is scale because it crop the images and it has not been used in the coil image. So let's show you that real quick here. So we can say content is scale equal. We can pass the content is scale that we created. And again, we are having a bit of problems. So let's see what is that? Not find a parameter with this name. Okay, we need to, we need to add this outside of this shimmer params. Okay, let's put it here after, after the image URL. So we can say content is scale equal L. And let's run it again and see if this resolve the problem. So it did not resolve our problem completely. Also, we have to we had to apply the inner padding in our screens because we also seems to forget that. So these are in the paradigm has not been applied. So let's apply this inner padding. So for that we need to create a medic modifier. So we can say Value Modifier equals modifier, parodying. And here we can say in our padding. And then we need to applying this inner padding into our image tab. So here we need to provide the final parameter as a modifier. So we can say modifier. And let's run it again. And it did not run again. So after doing some debugging and testing, I realized that I have forget to call this main screen in our main activity. So that's why we could not get anything on our screen. So let us just call the main screen in the onCreateView function. Oncreate function in main activity. And then we can run that. So let's do it. And it hasn't been install and about to launch. So we will see. So you can see that we have managed to run that, but not the way we wanted. But at least we got something running. And seems like it is the problem with maybe a staggered vertical grid, something I missed. Maybe it's the width of the image. So yeah, we were able to run that. And so in next section, we will be fixing the issue to fix our grid. And we can also switch to the list tab. I can click here. So you can see I have not put anything inside the list is screen, so I just put this messenger methyl is tac toe. In the next section, we will fix our staggered vertical grid to display them properly. And I will see you in the next section. 23. Fixing Staggered Vertical Grid: So now we need to fix the home screen as it's only showing one column, but we need at least two columns. So I realized that I did a typo mistake when I was creating the staggered vertical grid. So here in this staggered vertical grid, in the shortest column function, the minimum height should be set to int dot max value and not to Min value. So we can actually log this column and see how it works. So just before we return the column, we can log it. So here we can say log d. And here we can say column. And then we can hit plus. And here we can log the column to see how it works. So we can run this app. So we can go to the logcat and such for the sharpest column. So you can see that with the minimum value, we are only getting one column. So you can see we never get the column one. Of course it is. Start with the view and indexed. So don't confuse with that. So you can see that all images on the first column and we never get to the second column. So now we can change it to max value and see how it works. So here we can say max value and then we can run it again. And then we can log the difference. So now we're getting all the images properly in both columns. We can also see that in the logcat. So we can just search for it. So now you can see that it is start with the column 0. So it starts with hair column 0. And the second image is placed in column one. So you can see that it's there. And then 0, 1, 0, 1. So you can see the pattern here, 0, 1, 0, 1. So it's able to actually put the images in both column. So that's it for this section. 24. Creating list screen: Let's now move on to our list image are listed screen to create our list image screen. So I'm going to close the emulator and I'm also going to stop the process. And let's work on our list is green. To create the list of images. Though, I am also going to get rid of this function completely. So first we will create a list image function to display a single image. And then we will create another function where we will pass this list image function in a lazy column to display the list of all images. Lazy column is a better version of RecyclerView, which is the, a lot less complex and also removes a lot of codes. So let's start. So let's remove this import. And we can say that composable function, left image. We need some parameters. So first will be the image itself, the image from data class. So we can say image. And we need to choose our water. The attack last second is going to be a function what selecting the image. So we can say select image. We have done this already. All right, So only the layout is going to be a bit different. Most of the things will remain same from the home screen. So here we can say long and then the unit, and then modify it. So we can say modifier, modifier, modifier. Then we will bring our surface. I can say surface. And it's going to require some parameters. So we can say modifier, equal modifier. And then I can say dot fill max-width. And then I also want to apply some padding so I can say padding or dot dp. And then we need to import the DP as well. And then we need the clickable feature, clickable function. So we can click the images. So we can say dot clickable. And we needed a clickable message with clickable function with the curly braces. So here we can say onclick. And onclick, we can say, we can just pass the Select Image function. And then here we can provide the image ID so we can see image dot ID. And then we can apply some colors. So we can say color, dark, color equal material theme, dark colors. And we can say dot background. And then we can also declare elevation, elevation in dot dp. And then we can finally provide a shamed for it. So we can change here and we can go with rounded corners here. And again for this I went to go with 38 ATP. So that was for surface. And let us remove the import from head. Sometimes it just appears. Now we need a constraint layout. So let's say constant layout and header. We can apply some padding so we can modify or equal modifier dot by adding a DP. And after that, we need to define the references so we can say value. And I am going with the same old image, pig, title and height. And then air, we can say create reference. Now we need to bring in our network image. So we can say. Network image. And for URL, we can say image URL or image URL. And for a modifier we can say modifier equal modifier. And then we can say.com trends as and we need to pass the variable. So we can say Image pig. Then we need to provide the scope. So here we can say then there were typically two. And we can parent. And then we can say end dot link L2. We can save tied tilde dot star. So we are linking the end of the image to the start of the title. So they can be side-by-side. Then we need to provide its aspect ratio. There we can say dot aspect ratio. And we can say 1 f. Then we can say it'll max size. And then we can clip it with rounded cardinal. So we can say dot clip an error. We can say a rounded corner chef. And we can provide the sides of four dp. Then after network image, we knew that title. So we can say x. And for text we can say, simply say an image dot, dot height in many dot title. Then we can apply the constraints so we can think more than fire dot. Let's bring it to the next line. So we can set dot constant as title. Then we can provide the scope. So we can say if Dart, dart link to and we can say Image pig. And so this will again tiled star. I start off the title to the end of the images, like side-by-side, like hair we mentioned here. And then we can apply some padding. Padding. And we can say horizontal equals DP. And then for height, we can say, we can just copy it. And we can say May dot height and air. We can tend the constraint to height. And we can hear, we can say star dot link to image dot end. And also we need that topping to be linked to bid bottom of the title. So we can say top dot link to tighten the part down. So in this way it will be linked below the title. And then here we need some padding body start at the top. So we can say is equal to L dot dp. And also we need topping by adding from top, so we can say or point DP. And yeah. So we are done for a single event. And now we need to create a function to display the list of images. So we can go above. And we can say that at composable, function, list and air we can say images. So we can differentiate, differentiate between these two. And here we again need the data class, the image detect laugh, but now we need it in a list. So we can say images. Here, we can provide lift, and then we can say Image. Then we need the Select Image function. So we can just say select the image. And our classical modifier. Modifier. Here we need a variable in which we can save the state of the list. So it won't have to recreate the state at every decomposition. In other words, it will always remember what It's already has and we'll keep adding to it as we scroll through the list. So we can say, we need to create a state variable. So we can say, well instead equal, remember Livy, lift, then we need a column. So we can say column and air. We need some modifier. Though here we can say modifier equal, modifier dot, dot the status bar padding to apply that external space which matches the height of this status bar side along the top edge of the content. It applied the additionality space with two matches the height of the status bar along the top edge of the content. Next, we need a background color so we can say dot the background. And we can send material theme dot, dot background. Then we can use the lazy clock column in the column is go. So here we can say lazy column and we can remove the content and set the state. So in this lazy column, we need to provide the state. So we can say the state equal, we can provide the state variable we created. So we can say state equally state. And then we need a content padding. So we can say content padding. And then we can provide the values for it by saying padding values. And we can then pass the values. So we can say for dot-dot-dot ATP in this lazy column. Now we need to provide the scope. So we need to add list of items. So we can say items. And again, we need the small breath is not the curly braces. So we can say items. We need items, not item. Sorry my bad. Let's see. We can say items. And here we can see that the items to the images variable we created. So we can say items equal images. Then we need item content, which will display the content by a single item. So we can say item content, and here we can say emit. We can create a image variable layer. And then we can pass the Lambda function. And then we can call our single image list image function. So we can say add, lift, emit an air. We can set the image to image. And we can set the selected image to select Image function. And that's it. That's it for this listed screen function. Now we need to call this list image function in our screens. So here we can say, as it's already showing some matter because we changed the parameter. List is spin. Actually we don't have the greeting function anymore. They add, we can say list images. And we can just remove the qualifying. And they call sign here. And we can pass the modifier. And hopefully it will run as we would like to see. So let's run and see if we get everything right. And the app is up and running. So let's click on the list image, on the list step. So let's click it. We got it in list of fashion, but it's too big. The image is too big. So we need to rectify it. So let's do it. Okay. So the hide things to be too big. So looks like we have Mr. Hyde Park in the image. So yeah, we need to provide the height as well. So let's say height, and let's give it a value of 64 dot dp. And hopefully it will resolve the problem. So let's run it again. Let's click it again and see if we have resolved the issue. So we have resolved the issue and we can see all the images in lifted. So that's it for this section. And in the next section, we will be working on our Detail screen. So if we can click on this link or in this image, we will see the details and description about this mountain. So yeah, I will see you in the next section. 25. Creating details repository & detail view model: So from now on, we will be working on to create the detail screen or our image repository app. So for that, we need a couple of components. We need that detail repository class so we can fetch the details of a single image. Then we would need a ViewModel class for details the screen. So let's first read the details repository. So in the repository packet, let's close these two screens. So in repository packet, we need to create a detailed repository class, though we can say details repository. So in this class we will inject the image DO through injection constructor. So we can say at in Jack constructor. And here we need a value for an image DO. So we can say private Val, image DO of type D image DO. Inside this class we will create a function to fetch the details of one single image. So we can say unction, get image by ID. And we need to provide the ID as a parameter so we can say id of type long. And then we need the Getty image from our image. Do that. We can say image, DO and get the image. And we can pass the ID as a parameter. So let's go to the image DO and we call the function again. So where we are querying this function in our detailed repository to fetch one single image details through this function. So that's it for the detailed repository. Now, we will create the view model or a detailed screen. So we can close this. And first we will create a package for retail is screens. So let's create our packet. We can say details screen. Now we will create the view model. So we can say a new class details view model. So now we will construct it inject details repository class in this detail view model class. So we can again say that injected constructor. And here we can say Buy went well, details repository. We can select the details, the depository. Then we need to extend this class to ViewModel so we can say colon, we will model. And we also need to annotate this class with the headed to V-model and notation here, where we can say that ViewModel. Now inside this function, we need a mutable LiveData variable for image details. So we can say private var. And that is core image details of type live data. And we need to pass our image data class so you can image. And then we can initialize mutable LiveData. Now we need a getter function for this mutable LiveData. So we can say value image details of type LiveData. And again, we need to pass the image data class. And then we can call our function. So we can say get. And then we can set a mutable LiveData, many details. So image details to this getter function of humility details. Now we need a function to fit the details from the repository using our image DO though we can say function get, emit. And we need to provide the ID of type long with capital L. Along. Here we can say our image details, notable live data. And we can initialize with details repository dot get damaged by ID. And we can pass the ID as a parameter. So ID. And then we need to rotate this function at workup trade. So we can say actor thread. So it should only be called on worker thread 2 runs in the background and does not block the main UI thread. Now we can finally initialize this view model by saying in it. And we can log this as well. So we can say log b. And here we can just say we need to import the tag, will just import that tag. And here we can say initialized detail view model. And we are done. 26. Creating Image Details Screen: So after creating details repository and details view model, now we can create the image details the screen. So let's create the image details file in detail is pin packet. So here we can say new Kotlin file. And there we can say image details. We need to select the file. So first we will create a composable function for the detail screen. So we can say add composable. We can say function, image, details, body. And we need some parameters. The first parameter is going to be our image data class that we can fit image. And then we need a function for going back to the main screen. So we can say press on back of unit. Now inside this function, we knew that column, so we can say column. And then we need some parameters part this column. So the first thing we need is the is crawling functionality in case of longer details the screen. So we can say modifier equals modifier. And here we can say dot, vertical if doll. And we can use the remember is clearly state this function. Then we need a background color. So we can say dot background. And we can choose the color from material theme, same material theme, dot, dot, dot background. Then we need to fill the max height so we can pill max height. So it will fill the hole available height. Then in the column is scope, we need to create the references bar, the details screens. So for that, we need a constraint layout. So we can say constraint layout and we can create our friend's death. So we can say value. So we can say Image, pig and the title and height. And what else? We need the details so we can image details. And finally, we need an arrow icon. We can press the back button and we can say equals create reference. So for going back to main screen, we can also just use the back button on the device. But it's nice to have this function as well to going back. So let's work on our constraint layout. So the first thing we need is the image. So let's bring our network image. We can say network image and URL equals. So we can say Image, Image URL. Then we need the modifier to constraint it. So we can say modify it equal modifier dot constraints and, and we can pass the image pig reference. So we can image pig. And then we need to provide the scope. So we can say top link to and we can say that parent dot-dot-dot. So the image will be always on top. Then we need to fill the max-width so we can say build max width. And we also need the spectrum of CO, so we can say aspect ratio. And I'm just going with the pointer to 0 F. So you can choose whatever the number you would like to. Now, we need the text for the image title. So we can say after the network image, we can say text. And F. For text, we can simply say image dot title. And we can provide some styling. So we can say style. And we can choose material theme, material theme, topography. And we can select, there are so many options. I'm going with h5, h5, then we need a overflow. So we can say overflow. And we can choose text overflow, dot-dot-dot ellipses. And then we need to construct it so we can say modifier. The modifier.com stands as and we can provide the reference for it so we can say title, then we can provide the Pope for it. So for the scope, we can say top dot to link to. And we can say Image pig dot bottom. So it will be at the bottom of the image. And then we need some padding. So we can say dot the padding and we can save for a start. We can say it well, dot-dot-dot DB. Let's import the DP. And then for the top, we can say fixed in dot dp. So it will have a padding of 16 dp from the top, from the bottom up the image to the top of the text. And then we can do the same or the iPad. So I will just copy this text and less detail and error. I can say image, height. And for typography, we can choose the body to. And we don't need the overflow for this. So let's gender difference for constant here we can say height. Actually for text we can add to both air as well. We can say text equal. We should provide a string here at Chile, so it would make sense. So we can say name plus, and then you may dot title. So we will know that it's a name for the mountain. And we can do the failure for the height as well. So we can say text here and here, we can say GHD height. And what else? We need to link it to the this title. So we can say title. Bottom. And padding can be same. And then we needed the last text for the details of the image. So we can do the same again. We can copy it and paste it here. And here we can say details. Let's go into capital N here we can say Image doctor. Title, id should have been a description of something. Okay. Okay. Image in metadata. No, we're not showing the description. So let's go back to our image data class. And C12 is the problem. Where is the data class? Here we have. Okay, so I have forgot to include the details. When value pair we can just say value and we can say disk and type is string. And I think we should be good. So get back to Image Details. And here we can say image description. And for typographically, we shoulder, let it be body two. And we can link this to hide. So we can say hide, dark bottom, and padding can remain same. After this, we needed the icon or the back button. So here we can say icon and we can choose the image vector. So we can say image vector, icons, dot-dot-dot, varied. And here we can select the arrow back, arrow back our description. We can just pass null. You can pass any string you want. And then let's, let's go to the next line. Here we can provide that tinted color. We can set tint and we can say collab dot white. Then we need our modifier to constraint. So we can say modifier, modifier.com as we can say arrow, then we need to provide the Pope. So here we can say top Blinker to parent, dot-dot-dot. So it will be on the top of the parent. And we also need some paddings. We can say padding and we can provide the parenting of 12 dB. And we need to make it clickable because otherwise there is no point of having the icon. So here we can say clickable. And in this, we can provide the onClick function. The on click. We can say curly braces and we can say a press on back on SHA-1. And that's it for the body of poverty image details. And now we need another composable functions so we can observe the details of the image through details view model. So we can go to the top. And there I can say at composable function error, I will say image details. And in this function, we need the detailed 3D model as a parameter. So I can say ViewModel. And I can select the detailed 3D model and press and back function to get back to my screen, we can say press on back. Inside this function, we need a variable part details. So we can observe the detail. So you model. So we can say value details ON image. Question-mark. And we can say by ViewModel, we can select the image details that we created in the last section. And then we can say observe as a state. So while we also need to import the time, the composer and time. So it is starts observing this LiveData and represents this value and we're estate. And every time there would be new value posted into this live data, the returned to state will be updated and it will cause the recomposition of every value of this debt. So now we need to run a function on the civil details variable. So we can fetch the details of the image. So we can say details for Shen mark and then say dot lead. Then we need to create a image variable inside this leg, let function. So we can say Image and then followed by lambda expression. And then we can call lava image detail body. So we can say image details about D. And we can just say image. And we can pass the another function for press and back. So we can say press on back. And we need to remove these curly braces. We don't need those. So this led function is then in line function, which calls the image body functions with the image as an argument and it returns the results. So that is for this section. And in next section we will create route. But the details screen. 27. creating routes & navigation: In this section we will create doubt and navigation composable for the image detail is greens. But first, let me do a correction in this image details file as I forget, to replace the constant for image details. So let's do that quickly. So here in details we need to constant it as the image details. And now we are good to go. So let's clear that out for image details screens in the main if clean file. So in many screen, we need to create an object for the many details. So we can say object image details of type nav is green. And add we can create the route, so we can say Image Details. Then we need a constant, variable route with an argument. So we can send inside of this object function Const value. And we can say a root width argument of type string. And we can say Image Details. Forward slash. In curly braces, we can pass di, di for image, so we can say image ID. Then we need another variable or the argument itself. So we can say const, val are women. It's going to be same type is string. And there we can say image ID. So that's it for the class. Now we need a navigation composable in main screen function. So in provide window inserts after the home composable navigation. So after this, we can create another navigational composable. So we can say composable. And in this navigation composable we need two parameters around and argument. We can say here, route. And we can say Navi screen. We already have equal. So we can say Nivea screen dot, dot image details. But proud with our woman and bought the arguments. We can create a list of arguments. So we can say our women and air, we can say let stuff. And in this list off, we can provide the nav argument. So we can say never woman. And in this never moment, we can say Navi screen image details argument. Then we need to provide the type of argument. So the argument is imaged ID and its type is long. So we can say type equals nav type. And we already have a bunch of four types, but we need the long type. So we can send nav type type and we can bring it to the next line. Here we need to create the back stack entry. So we can say back stack. And three. Followed by lambda expression head. We need the details view model. So we can say value. We'll model equal L to view model. And we need to provide the details we model so we can say details we will model. Then we need to ever defense for the image ID. So we can say value image ID equal. We can say back is stack entry dot r woman. And then question-mark dot. We can say get long because it's a long time. Get long and we can say nav is clean, dot image details, dot argument. So as soon as we click on an image, we will have the reference of the image ID. And we can pass that ID to get image function that we created in details we model. So we can say we need the Getty Images function from the viewModel. So we can say ViewModel dot get emit. And here we can pass the image ID that we just get from clicking. And it said type mismatch, required long, found long. So both of them are long. Okay, Here we forget to return the composable in the image ID where loops where we need to say. But Denmark, Poland. And we can say, and I'd be done at composable. And now it has gone. Now we can call the image details when, after getting all the required references from the back is tech entry. So we can say here image details. We need to provide the viewModel. So we can just say, we can just pass this view model and then we also need the functionality to go back to the man is cream. So here we can call the navigator function. So we can then nav controller dot navigate up. So that's it for the image details is green route. And we also need to provide the route when we click the image in home is green or list is screen. So in home route composable here, we left this select Image function. So now we can say here, nav controller, navigate. We just need the Navigate, navigate up. And here we can say colon, colon, double quote, and we can say dollar sign. And then we can send our screen image details, dot route. And then we can say a forward slash and then dollar, and then we can pass it to it. So now if we click the image in home aspirin or list is screen, it will take us to the image details is green. So now we can run that and see if we did everything right. So let's run it. So I'm going to append my emulator. And I'm just going to run it. And it up. And oh, the app has been crashed. So let's see the logcat. So let's see what happened at Chile. Room cannot verify the data integrity. Looks like you have changed the schema, but forget to update the version number 0. Okay, So, yeah, in the last section, when we change the image data class. So yeah, we have changed the image data class. And so we have two options here. Either we uninstall the app from the device, or we can increase the version number in our app database class. So let's increase the it and see if it is start working. So here I'm going to say two and I'm going to run it again. And let's see if it will resolve the problem. So it's about to install. And now it's up and running. So let's click it and see if we get the image screen. And here we are. We are able to navigate through the image detail screen. So here we can see the name appears Mount Everest and height. And they're the little details. So we can actually zoom in the device to see a little bit wetter. It looked like 21 June. And we can go back by clicking the arrow tool. Let's click on another image. And yeah, I think it's working. So it's looking good. And you can play with the type of graph P and funds to increase the font size because it looks like it's looked too small. So you can play with that. 28. Conclusion: So guys, that's it for this course. And I hope that you'll learn quite a lot from this course. Now I think you are ready to make an app by yourself using jetpack compose. And by now, you know how powerful and convenient jetpack composes by decreasing at least half of your work. And by removing the XML part of UI. You must also notice how easy it is to create a list in dead pet compose compared to XML best programming. Now, with jetpack compose, you don't need to create RecyclerView and adapted for a RecyclerView. Introduce a lot of work for sure. So go ahead and find some free API on the web. And there are plenty of them if you want to make an m by yourself or better, if you know how to create your own back-end, then you should create your own API and make an app to connect the API. It does not have to be an image repository. You can make any IP want. So goodbye for now, and I will see you soon.