How to Build a Note App with Jetpack Compose, MVVM, and Clean Architecture

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Welcome to our journey through clean architecture with Android and Japan compose in today's fast-paced world building robust and maintainable Android app is more critical than ever clean architectures offers a structured and modular approach to development promoting code readability scalability and testability as Robert C Martin said clean architecture is the art of arranging code for understanding between us as we explore the principles of clean architecture and the beauty of Japan compose let's create elegant Android apps together let's get started okay so here is what we are going to build so we're going to have here a simple note application that is going to guide us to learn the in architecture and how we can easily implement this using jpa compose so basically here we're going to persist our data using room database and the UI is going to be built using jpa compose so as you can see we have here a clean interface by having two tabs here so we have a home and also bookmarked which can be easily filtered from the database so for example here we can just easily click this button here and basically this can be easily be fetched inside our bookmark and basically we can easily click here for example a not and here we can update a node so for example here we can say title updated and whenever we click this button we're going to update our note and the next case here we can easily just create a new knot so for example here let's write new notes okay so this is just a simple application and basically here a new note is going to be added and we can easily delete this node here and the note will be deleted okay so basically here we have mainly two themes so for example here we can easily navigate inside here and change our Dark theme and once we navigate here we have this stack theme and also we have a light theme so without any further delay let's get started so before even we start to write any piece of code what should we Bola learning clean architecture um as of now you will understand that clean architecture is really important as for you because we have several reasons so that we can easily make our code more clean and also more readable so we have the code maintainability so clean architecture is going to promote a clear separations of concerns which we can easily maintain our application also we never want to scale our application to add new features and other things it's relatively easy so for this case we have a scalability in our advantage also we can easily test our application by using this modular design which can easily enable us to perform unit tests and also different type of testes and also adaptability to change so in the ever evolving world of software development requirements change frequently so clean architectures flexibilities enable developers to accommodate these changes smoothly so all in all a learning clean architectures impulse developer to build maintainable scalab foreign application that adapt to changing requirements and stand the test of time so for this case that's why we want to look at how we can easily create a clean application okay so now in order to get started here you can easily get an initial project from the GitHub repository that is provided in the description box below so we have here the starter code so the first case here inside www.redofile I have added several dependencies which are going to help us whenever we want to create this application so we have here the room database DACA Hills and also we have the compose from dependencies which we are going to use here and the next case here we have inside our theme Here I have added colors which we can use them inside our theme so for now these are just great so we have not used anything we are going to use the default theme and then whenever we progress through application and complete application then we are going to worry about the look of our application okay so now let's create here our first layer so the first layer is going to be the data class so this data layer is going to help us to fetch the data so we can easily fetch this data from our local database and also from the network so Rockies we're just going to focus on the local database by using room database so the first case here we want to create a new package and we can just call this data layer it's just going to be the layer of our data now the next KCl let's create a a new package and for case we can just create a package for local and this is going to store the data from our local database the next case let's create here a new package and call this model which is just going to be the model class or the models which we have so for our case we are going to create here a new coding class or file and for our model we want to create here a node using room database here we can easily annotate this with ADD entity to create the table we want to set up here our our room database so for this case let's create here and we want to make this to be a data class okay so the first case let's create an ID it's just going to be of type long and initially we're just going to give it to be zero okay so our table here we can easily change this to Beta with the table name and this is just going to be of nuts the table name is going to be named notes so the ID here we have to tell a room database hey we want this to be our primary key so we can just call this to be our primary key and we want to Auto generate the uh this ID so we don't want to manually insert our IDs the next case here we want to obtain the title which is just going to be of type of string let's press Ctrl D here to duplicate this and for this case here we have our content and the next case here we want to obtain the created that we can just call here created that which is just going to be of type that okay the next case here we want to check if this is going to be bookmarked or not so we can create here variable and check is bookmarked and by default this is just going to be false okay so now here we have our table or the schema of our database the next case here we want to Define now the method that can easily be used to access this database here okay so for this case let's create here a new coding class or file and we want to select the interface okay so here we have our Dao and we have to tell room database hey this is just going to be a dial so we can annotate this with patada which means data access objects and the next case here we want to write now the method that can help us to fetch the data inside our database or communicate with the sqlite because room database is just an abstraction layer between the database and our application so for this case let's create here a new function and call it girl or not so the first case this method is going to return us with all notes we can create here a flow and this flow is going to return us with list of notes LS import here recording flow and the notes okay so we have to write here a query which is just going to help us to Define an sqlite statement that is going to help us to fetch this data for the first case we want to select everything from not stable so you can write here from notes and we want to order this and we want to order this by the created date so for this case it's going to return as the latest to be at the top okay so this one is going to return us with all of the notes which we have the next case we want to fetch a specific note by ID so for this case let's create a new function and call this get not by ID and here basically we are going to receive an ID in terms of long and this is just going to return us a flow of a single note now let's just press Ctrl C and copy this and press here Ctrl V so this is just going to be similar but here inside the order by we want to also add another condition that is going to help us to filter our database so we can just easily check here where the ID is going to be equal to the ID that is going to be provided so for this case we can easily filter our database by using this get node by ID by using this where close here okay so this was the first method that is going to help us to fetch our data in terms of by ID now the next case here we want to insert so we can use the convenience methods so let's create here a new function and call this inset so this is supposed to be a suspend function because we are going to perform here operations inside our database and we are not going to return anything so for this case we want to call this not here and we have to tell a room database hey this is just going to be an insert method and basically we have to provide here the uncompleted strategy which is going to help us whenever we have SM not with the same ID to replace it so for this case we can just call here on conflict strategy and call it.3 plus and this is just going to replace that particular note so you can note here we are not using suspend function here inside our get node by ID but here we are using a suspend function and this is because here we are returning a flow and flow handles its own creatine so it has a quality and scope and handle everything asynchronously but however here we are not returning anything so we are performing database operations so we have to accommodate the the operations or the synchronous operations which you are going to have so for this case we have to use a suspend function and then we can easily handle this by using a correcting scope okay the next case here is whenever we want to update so this is just going to be similar so let's just press Ctrl D here in order to duplicate this so instead of insert here we can just call update and this method is going to update and inside here let's call this update and this is going to help us to update our note now the next case here is to delete a not and this is going to be similar to this one but let's create a suspend function and call this delete and basically here let's pass in an ID of type long so we don't want to delete everything from our database now let's just add here add delete Sorry at query and here we can just call delete from notes and we want to specify here a condition where ID is going to be equal to the ID that has been provided so this one is going to help us to delete now the next case here we want to filter our database and get bookmarked notes so for this case let's create a new function and call this get bookmarked notes and this is just going to return as a flaw and a list of nodes because they can be many notes that have been bookmarked okay so the next case here we have to provide a query so we can just call this add query and now let's provide here a select everything we want to select everything from nodes and we want to provide here a condition where is bookmarked and this is just going to be equal to 1 because here inside our room database we are not going to be inside our sqlite we're not going to be saving here for example true enforce otherwise it's just going to save it as 0 and 1. so for this case we want to select one for true and zero for false so for our case here we are going to provide here to be equal to 1 so that we can return bookmarked notes the other case here we want to order this and we want to order this by the created that and we want to make them descending okay so this one is going to give us our bookmarked notes now the next case here as you can see inside our node here we are using the debt and this debt here is not going to be the data type that sqlite understand how to save it so for this case we have to create a date converter so let's navigate inside here our logo and create a new package and call this converters and inside here let's create a new coding class or file and call this that converter okay so this is just our data converter here and basically we're going to tell room Hey whenever we want to save the data type that is dead then you can easily use this methods here to help you to convert this type of data and save it so for this case let's create here add type converter and create here a function and call this to that and this is going to tell room database Hey whenever we want to convert this to a debt so the parameter here is going to be a debt in types of long and this is going to return us with address okay so in order to return here at that we can just call here return and call our date and let's use here a lettoscope function and create a new debt and pass in here to be it okay the next KCl let's just press Ctrl C and let's press Ctrl D in order to duplicate this and instead this to that we can just call this from that so we want to convert this from debt and basically here we are going to have a debt in terms of debt and here we are just going to return long so we're going to save this as long inside our database so for this case we can just call here our date parameter and call time which is just going to return us with a long with alarm so basically here what room database is going to do is going to look for these methods so this one is going to for example whenever we are saving our data to the database then it's going to use this method and convert a debt to a long and whenever we want to restore this from long to that which we want to use it inside the application then basically we can use these to that here and we can easily now save our application okay so now we have finished to create here our data the next case here is to create now our database class which is just the entry point through our application so now let's close everything here and create a new coding class or file and basically you want to call this not database and this database is going to inherit from the room database and we want to make this method to be abstract and we have to tell room database hey this is just going to be our database class which we can use it to inherit we can use it to access our data so for this case we have to annotate this with that database okay so the first case here we have to provide the entities so for our entity we have only a single entity and that is just a not so if you have more than one then you have to add them here because this is just an array as you can see here we have a notch and we have to call here the refresh to this type of class the next case here is just the version so for her case this is just our first division this is just going to be useful whenever you want to migrate your application from one database schema to the next one so for case we have only the first time here then we want to call here export schema to force so we're not going to perform any type of database migrations the next case here we have to tell room database hey we have a type converter that you have to use whenever you want to save type of this data so for cases just the date so you can just call here type converters and not type converter now inside here we can just provide the value which are just going to be the classes that we have and this is just an array and basically here we can just call our data converters and we have to provide the refresh to this type of class so now room database knows everything here which we require the next case here we want to be able to access our scammers so for this our data access object so in order to provide the access to this we have to create another abstract variable and this is just going to be the note down so for a case here we have only a single dial so if you have multiple nodes then you can easily provide similarly as how we did here by providing abstract vowel not Dao and everything is going to look perfectly so our room database is set up for now so let's click here build see that everything is okay or if we have any problem and fix them before we continue now everything is built correctly and we don't have any errors for now so now I think our data layer is almost complete so the next kcr let's create a new layer so now let's create our domain layer let's create AI package and call this domain and here now we want to create our repository now let's create it so inside here we are going to create a repository which is just an interface and we are going to implement this repository inside our data layer and that is going to have a concrete implementation so for this case we have the structure and then we're going to implement it inside our data layer now let's create here a new coding class or file and select interface and here we want to create our Repository okay now the first case here is to provide a method for accessing our database so the first case here we want to get the notes so you can just call get all notes which is going to return us with the flow let's import flow here and it's going to be a list of type nodes okay now let's import here which is just the note inside our database module the next case here we want to get the node by ID and we can easily pass in the ID to be of type long and it's going to return us with the flow and it's going to be of type nodes which is going to return as a naught the next case here is when we want to insert so we want to create a suspend function and call this inset and basically we want to pass in here and not the next case is when we are updating a node so you can just call update and basically here we can just pass in here the knot which is going to be updated the next case is to delete a note just call this delete and pass in here the ID which is just going to be of type long the next function is to get the bookmarked notes so you can call this book and this one is going to return as a flaw list of type notes okay so now we have here our repository so we want to create the repository implementation and this is just going to be created inside here our database so for this case let's create inside here our data and create a new package and call this Repository now inside here let's create a new coaching class of file and call this not Repository so now we have our repository implementation which is just going to inherit from our Repository now the next case here we want to inject this class because we're going to use dagger Hilt so for this case we have to annotate this with ADD inject in order to tell the health hey we want this class to be Constructor injected and with darker Hills you have to pass in this secondary Constructor so that you can easily provide the dependency which you require so for a case we want to get the knot down okay now let's press Ctrl I and implement the method that are available okay so the first case here we can easily implement this get all nodes so whenever we call this function we want to return a note down and call gets all notes it's just going to return us a list of notes the next case here is not by ID so similarly we can just call here return and call our Notch down and column get node by ID and pass in here the ID similarly here we can just insert a note so here we are not required to return anything so we can just call here or not now and here we want to update the note so we can just call update and pass in here our note which is required to be updated and on delete here we can just call or not dial and call delete and pass in here our ID get bookmarked then this is just a similar so you can just call here return not Dao and get our bookmarked notes okay so inside here our that layer we have our not repository implementation which is just implementing the repository that is provided inside here a repository so this is going to help us when we want to test our application so we can swap up with different types of repository implementation and have our our database or anything tested effectively so here inside our domain layer we are going to write our business logic that is going to help us to separate the concerns of our application so we have the data layer that is responsible with only the data and we have the domain layer that is responsible only with the business logic and then we are going to have a presentation layer where we are going to add the data about the UI related text so for this case I think everything is complete inside here our data now the next case here is inside our report inside our domain here we want to create our use cases which we can easily now start to create here now let's create here a new package and call this use cases okay so if you're wondering what is the role of use cases so in the domain layer of clean architecture use cases play a central and crucial role they represent the application's business logic and encapsulate specific user interactions or operations use cases act as the bridge between the applications called business rules and the outer layers which are just the presentation and the data layer so for this case we can use the use cases here in order to communicate between these two layers so for example if we want to communicate from our presentation layer going directly to our data layer so we can use these use cases and then communicate between these two layers and this is just really a robust way of making our application so overall use cases in the domain layer act as the heart of the application orchestrating and executing the business logic while keeping the core functionality isolated from external concerns so these separations enables a cleaner and more maintainable architecture from watching robust and flexible application development so for this case let's create here a new putting class or file and here we are going to create several types of use cases so for our case we are going to create a use case for update for example if we want to add or update or do anything so for a case let's create here this to be add use case so basically we are using dagger Hills so we want to construct and inject this class so you can just call here at inject and pass in here our Constructor now the next case here is to provide the dependency which we require so for a case here we want to get the repository so we can call Private wow and create the repository as you have not here we are not using the repository implementation but the interface which we have so whenever we provide these dependencies we are going to tell dagger Hills hey you can use this whenever you want to provide this type of repository then use these three repository implementation so during testing we can easily swap with any type of repository here so for this case now let's create a function that is going to help us to execute this so basically let's create here a suspend because we are going to add or we are going to add a data we want to call here a suspender function and we want to call this invoke and basically inside this function we're going to pass in here and not let's import the note and from our local models so what we can do here we can call our repository.inset and pass in here or not okay so this function here now works but one thing which we can easily make our code more readable is by adding an operator a modifier which is going to basically make this class to be called as a function so what do I mean by this so for example here when I call inside here uh our operator I can just call this operator here and we are going to omit the need to call for example add use cases dot invoke so for this case we can easily just call here for example add use cases and add this so basically this operator here is going to make our class to be able to be called as a function so as you can see whenever we had our composable functions when we want to invoke for example a callback we can easily use dot invoke or provide the parentheses directly here and that function is going to be invoked so this is just a similar to our case so we want to make here our use cases to be more readable so for this case we are going to omit the need to pass in this invoke here however we are just going to pass in here the parameters or the parentheses and pass in the needed parameters and make our function be executed so you're going to see this in action when we write our code so for this case we have our add use case the next case here we want for example to when we want to delete a node so let's create here a new putting class or file and we can just call this for example delete not and similarly here basically we can just call for example at inject and we have to pass in here the Constructor and create a private variable and pass in here our Repository now this class here also we can easily call our suspender fun and here let's pass in our operator and we want to call this invoke and basically we never want to delete we have to pass in here an ID so for this case let's pass in here the ID and we can easily just call here our Repository dot delete and we can pass in here our ID and basically our function is going to be executed okay the next case we want to get the bookmark the notes so for this case let's create here a new cutting class a file and here let's create a class and call this we want to get the bookmarked notes so you can just call this you can just call anything so from my case I have gone with that now let's pass in here and inject and pass in here the Constructor and inside here now let's pass in our Repository now the next case we can just pass in here the operator function because this function here is going to return us with a flow so we are not required to pass in a suspend modifier so for this case we can just call here our invoke function and we want to return here a flow which is just going to be a list of nodes let's import the node from our modifiers okay now here we can easily just call here return our Repository and call here get bookmarked notes and we return our book mat nodes okay the next case here so as you can see here we are making these as separations of constant but a class is going to be responsible on doing one thing so this is just a clear responsibility of these classes so here we have a class that only performs adding of uh not and here deleting and not filtering of notes so everything we're just going to be passing here so the next case here for example let's create a new coding class and we're just going to call this get all notes so for this case we can just pass in here at the inject and pass our Constructor and pass in here on private variable and we want to get the Repository let's pass in here our operator function and call this invoke again and this is just going to return us with the flow and this is just going to return as a flow with a list of notes so basically here we can just call our repository dot get all nodes and this is just going to return us notes so simple as that now the next case here let's create a use case for getting and not by ID but let's create here new coding class so similarly here we can just pass in here and inject and pass our Constructor let's pass any private valve and here basically we want to pass in our Repository now let's call here our operator function and call invoke and basically here we require an ID so this is just going to be of type int and basically now we can just call here a repository get not by ID and basically pass in here our ID sorry this is supposed to be a long and not an INT and this is just how you get a not by ID the last use case here which we are going to have inside the application is is updating a not so for this case let's just call this update not use case okay so updating here require us to pass in a suspend function so we pass in here a suspend and call this invoke and let's pass in here our notes and basically inside here we can just call our Repository dot update notes and pass in here our node which is required to be updated okay so now we have completed to create our use cases but it seems like we are doing some uh more tags which we are adding so this can be an overkill for a simple application but when you have a large application that is requiring maintenance and scalability this is really crucial so what's the the advantages of having here the use cases so the first one is just the business logic so use cases Define The Core Business logic of the application so they encapsulate the specific actions or operation that can be performed by the user so basically this is the first advantage of this so we have the business logic or the heart of application so the next case is just the simple responsibility so each use cases has a single responsibility focusing on one specific functionality or actions so this ensures that the business logic remains isolated and maintained easily the next case is just the independence from the Frameworks the use cases are framework agnostic they do not depend on any specific UI or data access Frameworks so making them easily portable and reusable across different platforms so for example when you use a costly multi-platform application or kmm then you can easily use this type of architecture and a substitute between Android and iOS or different framework for this case so the next case here is just the interactor button so in clean architecture use cases often follow the interactor pattern they act as intermediaries between the presentation layer which is just the UI and the domain layer so they receive requests from the presentation layer executes the business logic and then return results back to the presentation layer and the last one is just the stability so use cases being independent and having well-defined responsibility are highly testable and you can easily test your your application logic so this is your just really simple example so you can have a really complex use case here and write the the code so now our use cases are complete but as you can see here we are just injecting here the repository but now dagger Hill doesn't understand how to construct this type of dependencies as you can see this class here can be Constructor injected but it requires us to be providing the dependency about the repository which is just an interface and also we have other classes which we cannot construct and inject them something like a room database so for this case we have to create a dependency modules that dagger Health can use to provide containers for this type of dependencies and whenever these dependencies are required then dagger Health can inject them so for this case now let's just close all of this and outside here let's create a new package and call this Di and inside here we can easily now create our modules so the first module here is just the database module so you can just keep all of this data in the same class but for differentiations purposes you can just keep them in a separate object files so for this case let's create a new coding class or file and call this database module and this is just going to be providing the dependencies for our database so the first case here we have to annotate this with that module total dagger Health hey this is just going to be a module and create here and install in to tell dagger Hill to add components they should be it and for a case we want to call this a single term component okay so the first case we want to provide for example the house which we are going to have so for this case we have to tell the hills hey we want to provide and also we have to provide this to be a single tone so we want to have only a single instance of our Dao inside our database or inside the application not having multiple instances so for this case let's just call this provide not down and basically let's pass in here our database which is just the dependency that it is required to pass in and out as you remember inside our database class we created a an abstract function that is going to provide us with a note down and here we have to provide the return type so now Daga health will understand hey okay oh no no sorry here which is just the note down okay so that guy here to understand whenever I want a note down then I can just access this method which is going to provide me with the dependencies I require so you can just call here our database and this is supposed to be a notch database so now here we can just call our database.net now and this is what Daga health is going to provide the next case here is to provide the actual database so right now here dagger health is going to complain hey I don't know where can I get this because we cannot construct and inject the node database and for this case let's create here another function so let's just copy this and paste it here so instead of providing not down so we can just call here not database or provide database in short and one thing which we require here is just the context so you can just call here at application context which dagger Hilt will understand how to get it so you can just call this context what we want to return here is the not database class so for this case we can just call here our room database sorry we have to use this room here and call Dot database buildup and now inside here we can just pass in the context the next case is what we want to construct or what type of database we want to construct so for a case we can provide the reference to this node database [Music] Java now you can easily pass in here the name of the database so we are just going to call this nodes DB and call here dot build okay so now we have our database module the next case we want to be able to provide our repository so basically as you can see inside our domain our repository is just an interface and with DACA Health we can easily do this by using a bind method so for this case we can just create here a repository module okay and we want to make this class to be an abstract okay the next case here we want to bind this type of uh repository so for this case we can just call here we can create here an abstract function and call this bind Repository because we don't want to provide our repository implementation directly sometimes we can want to test it with a different repository so for this case inside here the dependency or the parameter we have to provide the repository implementation so dagger health will understand whenever I want to provide a repository which is just an interface so here the return type is just going to be the Repository which is just any interface so I have to use this type of repository so here we can pass in here a repository implementation and now we have to tell the health hey this is just at binds so you are just going to bind this type of dependencies and the next case we can just call this at Singleton which we want only to have a single instance of a repository throughout the application and not otherwise else now I think our dependencies are ready okay so inside here I'll present our data layer and the domain layer are complete and we can easily now provide the dependencies by using dagger Hilt and everything is looking perfectly so the next case here is just to create the presentation layer so for this case let's just collapse everything and let's create a new package and call this presentation and here we have our presentation layer now we can easily start to construct our view model and also our screens using gearbox compose so now here we have our presentation layer so the first case let's create here our new package and we want to call this home and inside here now we can create our home view model let's create a new coding class and call this home view model okay so now here we can easily call at inject in order to inject The Constructor because this is just we can easily construct and inject it and this is going to be inheriting from The View model class and the next case we have to tell Daga Health hey this is just a view model so generate a factory or anything which you know we can just call here Hill to view model okay so here what we want to get inside our view model is to get the use cases so specifically here we can just use the use cases which we require so for a case let's create here a private variable and the first one is just to get all notes use cases the next one is let's create a private variable and call this delete not use cases and also the updating whenever we click the bookmark we want to update the use case so we can just call this update not use cases so here we have three of the use cases which we require inside here okay so in Japan compose there are several ways of managing your state and for a case we are going to use the the data class to provide all of the states so for now we have only a single date inside here so let's pass in here and call this home state and basically here let's pass in our notes which is just going to be a list of nodes but before this we want to be able to manage our our state efficiently so for example if we are fetching and not we can easily just send it to make it more robust so for this case let's create here a new coding class and then instead of just passing here the notes directly let's create here a new package and call this common and inside here this command we are going to create a new coding class or file okay so inside this package here common we want to create a new cutting class or file and we want to call this screen view state so you can just call this screen view state or you can easily call it a resource holder which you can use it differently from different type of application but I want this to be a sealed the class and not just a normal class a sealed which is just providing us with more clean way of handling our states the next case here we want this to use out okay the first case we want to have for example whenever we are loading so we can just call this loading State and call here our screen view State and pass in here nothing so when we are loading we don't have any type of data here that's why we're just passing here the nothing keyword or the nothing object that means we aren't having nothing to display inside here or just show a loading spinner or anything else now the next test is when our data is successfully we can just call this success and it's going to be of type T and basically here let's create a variable and this is just going to be of type data and this is just going to be of type T because here now we are successfully we have the data and this data is going to inherit from the screen view state and let's pass in here the generic type and the next case is whenever we have an error we can just call this error and this error is going to be of those type of string so here you can pass in the error message or you can pass in here the the improvable error anything else so for my case I prefer to pass in here the error message and we can call this screen view State and here we don't have any type of data so you can just call this nothing so basically this is just a rapper class that is going to help us to manage our state whenever we page our data head to room databases so here we have a loading when we are fetching the data and we don't have any type of data to display and whenever is successfully then we can display the data to the user and whenever we have any error we can notify the user hey we have an error we did not succeed so and display this to the user so I find it more robust to make this way so if you have a an application that you can communicate to the network then you can use this similar architecture so I have a full course teaching about this the type of topics so you can easily check the link in the description box if you want to learn more okay so now let's just go back inside here and instead here of just passing here for example a list of notes so for example we can easily do this and this is just perfectly fine but now here we have different type of state which you want to manage so for this case let's create here our notes and it's going to be a state of of notes a list of note is going to be a screen State and this screen state is going to take a data type of list of nodes and by default here we want this to be using our screen view state dot loading because here we are just starting our application and we don't want to have anything that is going to be constructing a view so we have our loading State and whenever we fetch our data then we can change this screen view state to something else now the next case here is to create the state that can be easily observed from our view model to our UI layer and there are several ways you can do this with Jappa compose and room database and view model so for example you can use live data protein flow and also you can use immutable State flow and for a case we are going to use a mutable State flow in order to manage our state because it's much more robust in handling type of States so for this case let's create here a private variable and we want to add here an underscore and this is just going to be our state and basically here we can just call our mutable State flow and for our state here we want this to be our home state okay so we can just call here our mutable flow and we want this to be private for one reason so we don't want to mutate the state outside of the view model to avoid bugs because some other is unresponsible developers can change the state outside of the home view model and can bring a lot of bugs or it can be yourself and you have errors which you can are difficult to track so for this case here we have our date but it's private now in order to export this we have to create a read-only state law and this is just called the estate flow and this is just going to be of type home page so when you hover around here now let's add here they get a method first so you can just call here our state and convert this as state law so now when you hover around here you can see that a shared flow that represents a read-only state with a single updateable data value so for this case we have only this state as our read only variable we cannot mutate this even outside or yeah so this one is going to be mutated and this is going to provide us with the read only so this is just a concise way of managing your state inside our our room database and Japan compose okay so the first case we want whenever we launch our application or we navigate inside our home view model so that we can easily fetch the data from our database now for this case let's create here a function let's create AI private function and call this get all nodes okay so inside here we can just call it not use cases so here you can see inside our get not use cases let's press Ctrl click here you can see that this use cases we added here an operator so this operator here is going to function as this one here now let's call this get all use cases and instead now of calling dot invoke for example you can easily just make it as a Constructor here so as you can see this is the role of that operator keyword here and we can easily call it as a function so as you can see this get all notes now it's just like a function okay so here we have our notes but this returns us with the flow and we want to collect the floor inside here the view model so we can easily do this by calling collect or there is a simpler way using a cotton flow so you can just call here on each and basically here it's going to collect us with this type of flow now we can just call our state go to value and we can just create here a new home state and now let's construct here the notes and and basically inside there on each year we have a successfully data so you can just call here our screen view State and call Dot success because our data is successfully fetched and basically pass in here it's now the next case is when we have an error so we can just call here catch and this one is going to give us an error so for this case let's just copy this and paste it here so instead here of success we are going to pass in here error and basically here we can call it Dot message so here we have a catch so whenever we have any throwable which is going to occur here then we're going to catch this and send it to be an error and now we have to tell where to launch this type of kuratine so basically here we can just call launch in and basically call in here Azure mode scope so this is going to help us in creating the cool routine and also castilling the kuratine Scopes which are going to be produced whenever this type of view model is going to be cleared and this way is just a concise way of managing a kotlin flow so we have here this function which is going to be called whenever we create our view model so we have to create an init function and call this get all nodes and basically now here our application when is launched then we are going to call this method and get all of the nodes now the next case is whenever we want to delete a note so let's create here a function and call this delete which is just going to be of type long so here we can easily just use our view modoscope and call here our delete notes then pass in here the note ID and our node is going to be deleted sorry I'm just calling here the delete node so we have to call delete not use case here okay the next function here is the on bookmark now let's create here function and call this on bookmark okay so this function here is going to be passing as a naught and inside here now we can just call our viewmodoscope.launch and basically what we want to do here is to update our bookmark and because we have a note here and we want to update it so we can just call here our update not use case and call in here our not and we want to change is bookmark so you can just call here dot copy and check here is bookmark and what we want to do is we can use here our knots okay so our view model is complete here for the next case let's just create here a new uh the screen and for this case we can easily create here a new coding class or file and then call this home let's select file here so here we have our new home screen and we can easily it's now start to be at our home screen okay now let's create here a new composable and this composable we can just call it home detail and let's make this to be a private function so the next case here we want to pass in parameters which you require so the first case let's pass in here the notes which is just a list of not the next case here we can easily pass in the modifier and also the Callback whenever the bookmark changes so you can just call this on bookmark change but whenever the bookmark change here we're going to receive a note and return here a unit the next case is whenever we want to delete so we can just scroll there on delete and this one is going to give us the ID on type long and return a unit also they are not click whenever the note is going to be clicked and this is going to give us the ID every time here a unit okay so the first case here we want to display this inside a lazy vertical Target grid or we have to pass in here several parameters which we want so the first case is the number of columns which you require to get so for a case we are just going to use two so we can call here our staggered grid and we use this fixed and pass in here the number to B2 okay so we can just pass in here the content padding the next case is just the modifier you can easily pass in to be the default modifier okay so here we want to Now display those items and we have a list so for this case we have to use the items and I want to get the index of each particular item so that we can draw the items as you have seen inside our design we have a light Corners differently on different type of items so for this case we're going to use these items indexed and pass in here the notes and for the case here we're going to receive the index and the item and the item here we can easily rename it to not okay so the second case here we have to create a card and we can easily do this by creating here a new composable and call this not card and inside here let's pass in the index which is just going to be off type int the actual nodes which we are going to have and again here we have all the properties which you're going to receive here so let's just press Ctrl C and copy this call box here and paste them here so we want to be displaying the items differently whenever we have different index so for my case I have gone with even numbers and also odd numbers so for this case we can easily check is even index so for this case we can just get our index and use a mode operator okay so what I have done here is just take the index and use the mode operator to divide this by two and if the remainder is going to be equal to 0 then we know this is even and if it's not equal to zero then we know this is just an odd number so for this case we can easily decide the shape of our card so let's create here a new variable and call this shape let's use here a win statement and we want to check is even index and we can create here a rounded Corner shape now inside here you can easily specify so for a case we want to get the top start and let's lighten as a statement here so if this is not going to be even then we can create this rounded Corner shape and we want to change the top end now we use the top start so for our case we are just going to use stop end and give it 50 f so this is how we can easily use our index in order to determine the shape of our card differently on depending on the index which you are going to have now the next case here is to check the icons so if we have the icons is bookmarked then we want to display a different icon and if not we display the icon differently so let's create this icon and use an if statement now we can check if the note is bookmarked then we want to return this type of icon and we have to use outlined not default and here we can just call bookmark okay now let's create our card so we have everything necessary okay so for a case let's pass in here the modifier and we want this to take the whole width so we can call fill Max width and give it a padding for 4dp the next case here is to define the shape and we have already defined the variable and then on click so basically here we can invoke our on not clicked and pass in here the actual node ID because now the card has been clicked so you can call here not ID and pass in here our node ID okay so the next case here we can easily create a new column and for a case we want this column to occupy the whole width so we can call here our modifier and give it a padding of 80dp okay so when you look closely here inside our knot or the node items here we have two text so we have the title we have the content and also we have these uh buttons here which are going to delete and add an item oh for Casey let's create our text so here we have to use the note and we want to create this first one to be a title so we can call here not the title the next case is to give the font weight so you want this to be bolder than the rest of the text and give it a max line so we don't want the title to occupy more than one line for a case the next case here is to define the style maybe the next case here we can easily provide espresso now let's add the content and here we can easily create a new text dot ellipses to show the ellipses that are K so there is more text coming here okay so we can use now our style and change the style of this text so we can call here material theme and we want to use body medium instead of a title because here we have our body now okay so here we have completed to create our two text now the next case is to add these buttons here and that is quite simple so let's create a row because they arranged in a row format the next case let's pass in here the horizontal Arrangement and we want to arrange them in a space between so we can just call here arrangement okay so the first case here we have this delete icon which is just on the top left corner so for this case let's just pass in here the icon button and we have to pass in the not ID so we can just call here node.id which is just the items that is going to be deleted now the next case is to provide the icon okay so we use the icon composable function and here we pass in the image vector and for a case we want to pass in the icons dot delete so here we have our first icon so the next case here we can easily now just copy this press Ctrl C and paste it here Ctrl D and instead of on delete here we can just call the on bookmark change and here we have to pass in the notes so you can easily just pass in here or not now for the icons here we can just use now the icons which we have defined is going to be different depending on the items which we have so here we have our item ready the next case we can easily just navigate back here now let's just call here our note card and pass in here all of the parameters which are required now let's add here the named arguments okay so indeed here we have our home detail which is just ready to use so the next case here is to add the actual screen which can be accessed differently from different screens so for this case let's create a new composable and call this home screen okay so the first case here we can just pass in here the modifier and pass in here the default modifier the next case is to get the state which is just the home state and here we have the on bookmark change so all of our parameters here are ready now we have to use the state and as you can see our home state here has a so for example when you go here we have a nuts and we have used here a screen State and this is screen State occupies mainly different three types of States so the loading the success and also the error so you have to accommodate this inside our UI so we can easily do this by using a win statement to scope the states so we can just call here our state DOT knots we tell the user hey now we are just fetching here the data the next case is when we are successfully so we have the actual data so we can check here is the screen view state DOT success so if this is the case now we want to get the notes so we can create here a variable and call these to be nodes and we can call here our state notes.data because now we receive the data actually so for this case we can just call here our home detail and we want to pass in here the list of notes and all of the parameters which are required the names to the color arguments to make it more explicitly clear so now here we have our home detail so the last case here is to determine if the screen state is going to be in in a state of error so for this case we can just check either screen view state so if we receive any error then we're just going to show a text you can easily handle this differently but for my case I'm just going to show the user and tell him hey we have this type of error and we can just call notes Dot message and if this is going to be nullable then we still that we have unknown error and here we can change the color so we can use here the material theme and pass in here the error the color scheme so this is how we can easily manage our home screen and create the states now the next case let's preview and see if everything is looking perfectly so for this case let's create a new composable and for case let's just call this preview home and here basically we are just going to call here our home screen and let's annotate this with at preview and keep here the show system UI to be true now the next case here is to pass in the state and here we can just pass in here the home view state inside the on bookmark change here and passing here empty Lambda functions so here we have everything but now whenever we preview here our screen because our home view state by default is going to have here the screen dot loading so our case we can easily create here some variables so that we can preview them perfectly so for this case I'm going to paste in here several data so as you can see I have created here a placeholder text with this type of text and inside here I've created a list of notes with different type of title and also different type of things so for this case we can easily preview our functions and see if it's correctly displayed so inside here our home screen our home state so we can pass in here the notes and we can just pass in here the screen view State and give it a success State and for a case we can just pass in here the list of nodes which we have so that we can easily preview this inside our screen so for this case let's just navigate here inside our split and click build and refresh now our preview is complete and as you can see here we have our the notes displayed and they are looking perfectly so I think nothing here is to change and we can easily now start to implement other screens so the next case here which we want to implement here is just the bookmark so here we have all the notes so the the nodes which are displayed here are both bookmarked and unbookmarked so for this case to create a new screen we can just navigate inside here and create a new package and call this bookmark and inside here let's create a new cutting class or file and create our bookmark view model okay so this class is going to inherit from the viewmodo class and we have to tell Daga Health hey this is just going to be at Health view model and the next case here is to inject our Constructor we can just call here add inject and pass in here the Constructor now here we want to receive several parameters so the first case here is the update use case so you can just call here update use case The Bookmark not use cases and the next case here is to get the delete note delete not use case so similarly to how we did with our our home screen so we can do the the same with a bookmark so we can just create here our data class and pass in here the bookmark state now here you can pass in other states so for my case I have only one state and this is just going to be a list and we can easily initialize this to screen view state DOT loading the first time now let's create here our state and we can use a mutable State flow and this is just going to be our bookmark state and we can initialize this by using a new double State flow functions or Constructor and basically pass in here our bookmark State as the initial State on okay so that was our mutable State now let's create a read-only state and this is just going to be a state flow that is going to pick up the bookmark state so now we have our state flow the next case here is to get the bookmark notes whenever we initialize this type of view model so for this case let's create a private function and call this get bookmarked similarly we can use here our filtered bookmarked notes and use here our operator function and call the on each and inside the on each here we have a success so you can just call here state DOT value and initialize this to a bookmark notes state and basically now let's pass in here our notes and we can use our screen view state DOT success and pass in here it as we have a successfully so we pass in here the data now after we collect the data whenever we have any type of error we can just easily call here catch in order to receive the error now we can change our state and here we can create our bookmark State and pass in here the notes and inside here so we can just call it dot message to pass in here the error which we can receive now we have to tell each words up to use to launch this so for our case we're just going to call this launch in and we want to call this view modoscope where it's going just to launch this type of flow now the next case is the function which is going to be called whenever the bookmark changes so let's create here a function then call this on bookmark change so these are the events which are going to flow to our composable color so we are going to receive here the note okay so we are just going to use here our view motor scope that launch because we are going to be changing our database so for this case we want to call update not use case and here we can call our notes now we want to change this type of note which is going to be passed so for a case we can easily check here is bookmarked and what we can do here we can call our naught dot is bookmarked and here we can use a negate value which is going to be if it's true then it's going to give us a first value so here we have our own bookmark change the next case is to define the on delete and call this delete not which require us to pass in the not ID and this is going to be of type long and we can call here our delete note use case and pass in here our node ID and this is required to be launched inside a few modoscope so we can call here launch and pass in here because this is the suspend function and we are calling this to uh change our database so now here our view model is complete the next case here is to create our home screen now let's just create here a new coding class or file then call this bookmark which is just the bookmark twin which you are going to receive okay so now here we have our bookmark screen now we can easily create here a new composable and call this bookmark for the first case here we want to receive the state and here we can pass in the modifier the next case here is just there on delete which is going to pass in here an ID and pass in here a unit the next case is just the on Note click so inside here our bookmark screen we can easily start now to create our screen so the best case we are going this is going to be similar to what we did inside our home screen so we have here our state in terms of bookmark state which uses a screen view state so for this case we can just use here a win statement and for this case we can pass in here the state DOT notes and now we want to check if his screen is going to be inside the loading state so we can just close the screen view so if inside the we are going to show here a circular progress indicator and let's check if this screen is going to be inside a success state so you can just call here screen view state DOT success if our class is this one then here we have to show our data and here basically we are going to show the data but not inside the staggered grid however we are just going to show here the data inside a a lazy column so for this case let's create here a variable and we can easily call these nodes and similarly here we can just call here state and basically here we can pass in our modifier now inside here we can pass in the items indexed then call here our notes and basically here we have to rename this to index and basically inside here we have our note card which we have already created and basically inside here we can pass in our parameters now the next case here we have our display state so here if our screen is display the next case here is to check if is pin is going to be in type of error we can just call this dot error and similarly here we can just easily just go inside here our home screen and copy this text here let's go back inside our bookmark State and paste it here so now everything is looking perfectly here inside our bookmark screen okay so everything is set up here inside a bookmark let's create here a preview function so we can easily navigate inside our home screen here and we have here a preview function so we can just press Ctrl C and copy this preview function let's go inside here a bookmark screen and for the part of modifier here we can just pass in here a default modifier and now everything is looking perfectly let's go inside our preview and see the preview so this is just the up review for The Bookmark screen which is looking perfectly for a case now the next case here which we want to do is to create the detail screen okay so for this case this detailed screen is going to be the last screen which we're going to create inside our composables so for this case let's just navigate inside here presentation layer and create a new package as usual this class is going to inherit from The View model okay so the next case here we want to define the injection so for this case let's create here our Constructor and inside here we are going to provide the variables which we require so when you look at our application we are updating our data which whenever we navigate for example from the home screen going to the details screen then we can easily update our data so for this case we have to pass in the ID and this ID is coming from our view our home screen or our bookmarker screen so in order to pass it as a dependency inside our detail view model we have to pass it at runtime and not at the compile time so for this case dagger health will not understand hey I cannot construct I inject this type of variables so how can I do it so for this case we are going to see something that is called assisted injection using dagger Hilt so let's for example here instead or inside our detail view model so we use that to inject to inject the other view models but for case here we are going to tell the girl hey we want to perform here assisted injection for the this class so we are going to call this assisted inject the assistant inject here is going to play a role here whenever we want to inject something from runtime or that dagger Health cannot cause cannot inject so for this case we are going to create a private variable and here we want to create the add a use case which we are going to use it the next case here is to create the get not use Case by ID because here we're going to fetch a particular ID whenever we want to change it so for this case let's create a private variable and call this get not by ID get not by ID use case which is going to help us to fetch the ID whenever we receive it so the next case here we want to provide the ID of that particular node which we want to pass it and here now let's just use add assisted to tell dagger Hilt hey this variable is going to be assisted when we are going to inject it so for this case let's just pass in here assisted and create a private variable and call this not ID which is just going to be of type long we're going to see how we can easily assist it to to inject it so I have not see how we're using rdu's case Factory and we don't want this here we want to use the add use case which is just add use case that we have created so the factories that is dagger Health which created okay so as you have not see up we are not providing ad view model Health here Auto DVA view model this is just because we're using here assisted injection so for this case we have to create the factories that dagger held or can be used to construct and provide the dependencies so the only dependence which dagger Health cannot provide at the moment is this one which we have provided here at assisted so for this case we have to create a factory that we can easily pass an ID at runtime so for this case let's create our SD class and this class is going to be a detailed view model Factory okay so this is going to inherit from the viewmodo provider so inside here we have one method which we can override so let's press Ctrl o and we can override this on Create and here we are going to return something else so here we want to pass in the parameters which you require so the first parameter here is just the ID and the next one is just an interface that is going to be assisting us for this particular injection in order to construct this particular or this view model so for this case we can easily create here below another class which is just an interface and we can just call this detailed so this is the factory that is going to help us to perform a injection so for this case we can just call here create and pass in here the parameter which we want which is just the note ID and this is just going to return us with the detail view model so this one is going to be used by dagger Hilt in order to provide the uh to provide the dependency for the view model so for this case here we can use we can annotate this with at assisted assisted Factory so this is going to be able to initialize our view model so for this case the next parameter here which we have to pass in is just this a class which we have created so I can create your private file and call this assisted Factory which is just the factory which we are going to inject and here inside we are supposed to return a class that is going to be of type T So for a case we can just call here return and call our assisted Factory method or parameter which we have provided there and call Dot create sorry this is just assisted Factory and this one is supposed to be a detailed assisted Factory so for this case we can just call here.cleat and pass in here the ID which we have so for our case we are going to pass in the node ID and we have to cast this as t and here we're going to receive an error and check the cast but this error is no meaning here so for a case we want to suppress it and remove that warning so I think here everything is ready for the part of passing our parameters and injecting our view model now the next case here is to create the functions or the event that can be triggered inside this new model and reacting to the UI State changes okay now we have to create here the data class that is going to hold up our details state the first case here we are going to receive an ID which is just going to be of type long so this is going to be crucial but this one is going to be crucial whenever we want to update our our notes so for this case we are going to receive the ID the next case is just the title which is going to arise from the user whenever they type it inside our text fields for example the next case here is just the content which is just going to be of type of screen and by default we can initialize these two empty strings okay the next case here is just if this one is going to be is bookmarked and this one is going to be of type Boolean and by default this is just going to be false and also they created that which is just going to be of type that and by default we can just create the date from which is going to give us the current date or the date that is going to be the not creating okay the next case here is we want to check if we are updating the notes so we can just call is updating notes and this is just going to be of type Boolean and by default we know that we are not updating the not otherwise else we have to set it up okay so here we can create our state and there are different ways of creating State using a jpa compose so for example here we can create our state by using a mutable State off so for this case let's just call our mutable state a double State off and here we can pass in our detailed state because we don't have complex States so it's just easy to manage this by using a mutable state of the next case here we can provide a private set because we don't want to change the state outside of the view model or our case Okay the next case here is to provide a variable that is going to help us to track if our ID our title and contents is not empty so that we cannot save something inside our database that is not written so for this case we can create here a variable in order to validate so we can call this is form not blank and this one is just going to be a Boolean so let's define here a get function and for this gate function we can just call here State the title is not empty and here we can add another thing which is just a state dot dot content and similarly this is not empty so this is going to help us to track those State and if there is anything wrong then the user cannot save this inside our database so we can see how we are going to use it so the next case here is to construct the not according to our state so for this case let's create here a private variable then call this not and this is going to be of type not okay now let's import here or not and Define here a get function and forget function we can just call State DOT run and basically let's construct here a new node according to our state and for this case we can just change our ID and pass in here every parameter which is required according to our state now it's just to put this argument on a separate line and everything is looking perfectly here okay so the next case is to create an initializer or a function that is going to be called whenever we initialize our our view model so let's create here a private function and call this initialize okay so the first case we want to check if this is going to be updating or not so here we can check is updating and basically we can check here our knot ID so we are going to pass in here by default that they're not ID whenever we are creating a variable is going to be equal to negative one so by default we never want to create a new node then the ID is going to be negative 1 which does not represent any type of ID of our existing nodes so for this case we can easily check if we are updating or not so if we have a valid ID from 0 going to other numbers then we know you have a valid ID so we are updating the ID and for this case now we can just tell that we are updating so let's just call here our state and we want to call state.copy and pass in here is updating and call is updating and now here we know that if we are updating and not then we have to update our UI to reflect this type of state now let's write here an if a statement and we want to check here the if we are updating then we have to get the note by ID for this case so if we navigate to our view model and then we are just having a valid ID so we have to fetch that ID through our room database and display it to our screen so for this case let's create here a function and call it yet not by ID so let's just collapse this for a moment okay so here we can just call a few modoscope so we can easily just call here.colect and basically here we can easily now collect our data so for this case we can just call our state and call state.copy and pass in here the ID which is just going to be the note dot ID that we have received so yeah basically we can just easily change this to be a naught and now we reference this node here and note the note that we are going to be constructing okay the next case here is just the title and we can just call here node.title okay so everything here is set up so we have fetch the knot and we have changed our state inside here by getting our note by ID so the next case inside here are in initializer now we can easily just call here inside our if a statement and call get not by ID sorry get not by ID and this one function is going to help us to fetch it and because we are using a state it's going to populate the data inside our screen so basically there we can easily change the the the data and this is just the good part of paper compose because here we have a declarative way of handling our data okay so the next case here is to define the events that can be changed to change this state here so as you can see we have the title content and it's bookmark so we can create here the we can create here our functions that can be easily used to update these particular States okay now let's create here a function and call this on title change and let's pass in here the title which is just going to be of the upper string so for this case we can just call State and call here our state.copy and basically pass in here our title will be equal to Tito okay the next case here we can just duplicate this and press Ctrl D so let's press this Ctrl d three times so instead of one title change here we can just call on content change okay the next case here is on bookmark change so we can just pass in here on so basically here we can just pass in a Boolean is bookmark so we can just call this is bookmark which is just going to be a Boolean and here we can just change is bookmark back to this is bookmark okay so basically here is going to update our note now the next case here is just a method that is going to be called whenever we want to add our data or to update our data so for this case let's create here a function and call this function and or update update or not because inside our node whenever we have an existing ID so we told the room database Whenever there is a conflict then they can easily replace that with the new data which we are going to provide so for this case that's why we are using this add order update and basically here we can just pass in here our view motorscope and call it.lunch or if you want another way you can just use an info statement and check between the node ID so if the note ID is not going to be equal to negative one then you can just call the ad you add use case or you can pass in here they delete the update use case so for this case we're just going to use this add or update use case so for this case we can just call here our add use case and basically pass in here the note which we have constructed so for this case we can just call here not and pass in here our knot and the note this is here constructed here the first time we constructed this by using our state so basically here we have everything and now we just call here add or update node and everything is going to be at added and updated okay so our detail view model is complete so the next case here let's create our detail screen okay now let's create a new composable and call this detail screen okay so this detail screen here is going to receive several parameters so the first parameter is just the modifier which we're going to be passing and we can just pass in here an empty modifier so it's just a good practice to pass in and modifier as the first parameter the next case here is to pass in the node ID which is going to be of type long the next case here is just the assisted Factory which is just going to be the detailed assisted Factory class which we have created from the previous time so the next question let's create here the navigator app which we can use as the button to navigate up our screen okay so here we're going to finish up this composable here which is just going to be the detail screen that is going to be used outside of this type of file so let's create here a new private composable so let's create here a composable and also call it detail screen and this is just going to be a private okay and here we're going to receive the different parameters here so the first case we can just call the modifier and check if it's updating so if we are updating or not and here we can just call this to be a Boolean the next case is just the title which is just the state which you're going to receive this is just going to be of type of string and also the content this is going to be of the Apple screen is bookmark which also is going to be of type of string the next case here we want to check if the forms are not black so you can just create here a variable and call this form not blank and this is just going to be also a Boolean okay so here let's pass in the events back to the composable color and these are just the Untitled on title change which basically here we can pass in our string and return a unit and the next case is just their own content on content change which is just of type of string that returns us a unit also the next case here is whenever we click a button so we can create here on button click and also the on navigate so at the moment these are just the parameters which we require to construct our composable okay so this is just this screen which we want to achieve and as you can see here we have this top section here which we can easily create and also we have the data that is displayed here so for this case this is just a really simple screen to implement for the first case everything is arranged inside the column so let's create here a column and here we want to pass in a modifier and we can use here our modifier.fill Max with the first case then we have to create the top section so we can easily create a new composable to make our composable more readable so let's create a new composable and call this top section okay for our top section here we can just pass in a modifier and pass in here a default modifier the next case we can just pass in here the title is bookmark which is supposed to be a Boolean not a string so I think here also is bookmark is made as a string so this is supposed to be a Boolean okay the next case here is just the on bookmark change so let's pass in here the on bookmark change which is going to pass in here a Boolean and return as a unit because when you look here at our screen we have a button that we can set the bookmark so if you want to bookmark this type so we can easily change it the next case here is just their own title change and also on navigate which basically here we have a dedicated button to navigate back to our home screen okay so the first case here as you can see our data are just arranged inside the row we can create here a row now for this case we have to pass in here the modifier so for a case we can just call here the modifier.fill max width and let's pass in here the horizontal arrangement okay the next case here is just the vertical alignment and we can just use here alignments.center press enter vertically now the next case here is just to check the icons so inside here we have several icons so we have these icons which is going to navigate us back then here we have a button a text field where we can insert the data and also here we have an icon which we can use it to bookmark this type of not so for this case let's create here an icon button and here we can just pass in the on click and for our case here we can just call the on navigate which is just going to be navigating us so for this case let's create here an icon and here we can just pass in the image vector which is going to represent that and as usual let's pass in here the content description to be now so the next case here we want to create the text field so because here we have two text fields and they look and feel similar so we can create a separate composable function here in order to separate our code a little bit so for this case let's create a private function and call this not Stacks build or if you want to use it otherwise you can remove this private modifier here and here we have to annotate this with ADD composable now for this case inside here we can just Define the the parameters which we want so this is supposed to be a d here and here first case we can just pass in our modifier the next case here is yes the value which is just going to be of type string and the next case is just the on value change the Lambda function that is going to return us with the unit and that is going to be the case so the next case here is just the labels which we have so we can pass in here the label the label which is just going to be of the screen for our case and also we can pass in here the label align so let's pass in here the label which we can just call this textile line and by default we want to set this to be now we can just reuse this composable here now for a case we want to create an outline the text field so we can just create or you can use a normal one so for my case I have decided to go with the outline text field and everything is going to work similar so the first case here we can pass in the value and here call our value and call the on value change I think we can just call this on value change and I think that reflects it very well okay the next case here is to pass in the modifier and another case here is to pass in the colors so as you can see inside our text field here they are somehow like transparent there so for this case we have to override the defaults so you can just call here our text fields okay now let's override here the container colors so for the disabled container color here we want to pass in to be transparent and also for the forecast container color we can also pass in here to be transparent and for the keys the indicator and focus the indicator color also you want to pass this to be transparent and the forecasts indicator color you can just make it also to be transparent so this one is going to make us our composable a little bit transparent okay so after we override here the colors we can easily change now the placeholder so we can just call this placeholder which is just going to be something like a label so you can create here in normal text and inside here let's pass in our text and here we can just call this in set and pass in here the label or the text which we want to insert here now for the text align here we can just call our label the label align which is going to help us to align this label and pass in here the modifier and we want to fill the max width so we can just call this fill Max width and for this case here our text is going to be the case so here we have to provide the modifier as the named argument and now here our next text field is just complete so we can navigate inside our our top section here and below this we can just create our notes text field so for the first case here we can pass in the modifier so as you can see here inside our text field we have passed e to fill the max width so we can use here the modifier and pass in here a weight of one f the next case is just the value so for the value we can easily pass in title and also the label you can just call this in the title so the label line or the texture line here so we can use our text text align and we want to center it so we can call here text align Dot Center so we can just Center it and the on value change here we can just pass in here their own title change and everything is going to look perfectly now the last case here is to create the button so this is supposed to go outside our icon button here and we can easily paste it here so we can just press Ctrl C to copy this icon button here and now below the text field we can just pass in here our icon button and now instead here of Arrow back we can just create here the bookmark so we can create here a variable to identify the icon first or we can check if is bookmarked dot bookmark remove if this is the case and if not then we can just pass in here the hills and for our case we can just call here our icons dot default sorry here we have to pass in the outline or here instead of passing the icon directly so we can just pass in here our icon as a parameter now I think everything is looking perfectly for our top section so for this case we can just sorry and the own bookmark change we have not called it so here instead of on navigate we can just call here our own bookmark change and because this on bookmark change is just going to return us with the Boolean we cannot pass in the reference directly so for this case we have to pass in here the parameter so we can just negate that is bookmarked and return it to the composable color in order to modify the state so if this is true then this is going to return it to be false because we are using this negation parameter or operator now for this case we can just go inside here our screen and let's call here our top section now let's pass in here the title okay so here we don't have the parameter for their own bookmark change so we can just create here their own bookmark change which is just going to return us with the unit so we can easily call here the reference on bookmark change and the list is going to be their own title change and call here on title change and last one is just there on navigate and we can pass in here there on navigate to this field here so we have our stop section for the next case here we can add a little bit of a spacer here so let's create the espresso or 4dp or let's just make it B12 so that we can easily differentiate this okay so now here we want to add the next item so we have here our top section so now we have to add this middle section here and as you can see the first case here we have this next field here so whenever we insert this data and insert here data we have a an icon here which we can be used to save this type of item so for this case as you can see whenever we just remove this data this is going to be hidden out or taken out of our composition tree so for this case we can use a control statement or we can use the animated visibility which can easily use to control this and we say that we want to use this is from not blank so if the form is not blank then we show this check mark So for this case the user cannot save the data inside the the database if there are no any data passed so for this case let's create a row and we are creating here a row because we want to align this to the end of our our composable so for this case let's pass in here a modifier and call this dot fill Max width which will keep this to the left of out to the right of our screen so for this case another thing here we can pass in the horizontal Arrangement so let's pass in here the horizontal Arrangement and we want to pass it to the end so we can pass in here horizontal Arrangement dot end now the next case here is to define the icon itself so you can just call here our icon button and pass in here the on click and basically pass in here the on button click which is going to be used to save it so for this case we want to display this type of Icon differently so if we are navigating to it we can display the icon to be updating or if we are just navigating to create a new icon then we can show a simple check mark So for the case let's create here a new icon and check here if is updating if we are updating a note so we can use our icons you can use this icon or else we can just use another icon so let's just copy this press Ctrl C and paste it here so instead of updates now we can pass in here a check which is going to be saving this to our database now let's create the actual icon that is going to display and here we can pass in our image vector and press in the icon and the content description to be now okay so we have here our button and that is going to be invoked whenever we want to save our data now the next case here is to add a little bit of a spacer so you can just press Ctrl C and copy this and paste it here okay the next case here is to call our node text field so similarly here inside our top section so let's just navigate inside our top section here and actually we called here the not text field so we can just press Ctrl C and paste it here and now instead of I2 here we can just pass in the content and for the part here we can just pass in the content as our label or our placeholder now for the textile line here we can just omit it completely and here we can use their own content change and basically have our text field ready to use so the next case here I think our detail screen is complete so we have this made it as a private so we can easily call it inside here our detail screen which is not private and expose it outside of this particular file so for this case let's create here the first case we want to get the reference to the view model so for this case we can call here our view model and here we want to construct the detail view model and give it the reference of what we want to build now the next case here is we are going to construct this using a factory so for this case here we have to pass in the detailed view model Factory now we have to pass in here the node ID which is just going to be the note ID which we provided the next one is just the assisted Factory so here we have to use the detailed view model Factory and not the detail the factory which is just an interface so this class here is going to help us to construct this view model so that's why we are passing here the model class then we are passing here a detailed review model Factory that can be used to construct it and here dagger Hilt will understand how to easily construct this so for this case inside here now we can easily obtain our state so basically this is just a state for composable and here we have a stateless composable so basically here we are just easily performing a state hosting which is just a common principle inside jpa compose now for this case we can just call here a few model so it is state in order to obtain that particular State now for this case we can just call here our detail this screen and pass in here the modifier sorry so here we are just recalling the same so let's pass in here the modifier and pass in the modifier to be from our detailed screen the next case here is to check if it is updating not and basically here we can use our state dot is updating okay so for the part here of on button click here we can use our view model and call here our add or update not and we can just call here our navigate app whenever we perform this function so if we add or update or not then we can easily navigate back to our screen and the last case here is just call there on navigate and basically we can just call the navigate app composable function here we are not invoking this and here let's remove this comma and basically here now our detail this screen is ready to use okay so now I think everything is looking good and we can easily create now the navigation and we can navigate from one screen to another screen so for this case let's clean up all of these classes here and inside here presentation let's create a new package and we can just call this navigation okay so there are different ways of navigating with jpa compose and you have to define basically two two things so the first case you have to define the composables and also their routes so in order to define the routes you can use any type of features but you used or defined by kotlin so for case here we can use an enumclass and this enumclass here we can easily call it spins and this basically are the screens which we have so for a case we have the home we have the detail and also we have the bookmark screen so to manage this you can use different type of things so from my case I have gone with these screens here or simply by using an enumclass so you can create a data class you can create a facility class or anything else in order to Define your route that's how you wish so because this is just a simple screen we can just create this or if you want to learn more about how you can handle navigation you can check my udemy course which is linked in the description box below so for this case let's pass in here the note navigation the next case here is the navigation host controller which we want to receive then the next case here we want to receive the home view model which we are going to constructed from the composable color also the bookmark view model and the last case is just the assisted Factory which is just the detailed assisted Factory so guys if you're getting any value out of this video please don't forget to provide a like And subscribe for more video so this is just helpful for the channel the next case here let's provide the navigation host so here we want to provide now the host and tell it what we want to navigate to so the first case we have to pass in the navigation controller and here we can use the nav host controller which is just like a steering wheel which is going to guide us Hey Now go to the details screen or go to the bookmarker screen so for this case we have to Define also the start destination which is just the destination which whenever we launch our application then we can see this so for this case we are just going to go use screens.com and this is just going to be our starter destination so inside here now we can just Define our composables where we can easily navigate to them so for this case let's create here a new composable now here we have to define the route so for our route this is just going to be the home screen so the route as we have defined there inside our start destination so we can do similarly and pass into being name so this route here must be similar any typos if you hard code them then you are going to get an error and not navigating to that particular screen so for a case we are directly using here an enumclass in order to avoid these typos okay so the first case here we have to pass in the composables which we want to be called and here we can pass in the state and basically here now we have to obtain the state and for our home view State we used a different way so we expose the state flow so for this case we can just obtain our states and initialize this by using a home view model so here we can use a by delegate in order to obtain directly the state and here we want to call colleagues as a state which is going to help us to collect this as a state now let's import the get values now here let's pass in our state and call here basically we require the state directly here the next case here is just the on bookmark change and here basically we can use our home view model and directly use their own bookmark change the next case here is just there on delete so we can call here the home view model and call here their own deletes or directly called the delete note the next parameter here is whenever the knocked is going to be clipped so here we can use the enough controller and call.navigate the one thing which we want to be handling here is whenever we navigate from one screen to another screen we want to pop up everything that is going to be available in that particular screen so whenever we navigate from one screen to another screen that the screen is going to be added to the back stack so whenever we press the back button then we are going to go to that particular screen so for example if we navigate to a detailed screen and then we navigate back again to the home screen and navigate back to the details screen so if the user presses this back button then it's going to be navigated to to the detail to the home screen and navigate it back to the details screen until to be able to quit the application which is not good for not good user experience So Below this we can create here an extension function that we can Define because we are being going to navigate differently so let's create here a navigation host controller and create here an extension function and call this navigate to single top then Define here a route and this is going to help us to navigate from one screen to another screen so this is going to be of type of stream and let's call here our navigate and pass in here our route and we want to be able to manage the screens which are added inside our back stack so we can call this pop-up queue so what we want to do we can use here our graph to find the static destination and pass in here the ID which is going to help us to fetch that particular ID and here basically we can just call server State and pass this to be true the next case we want to tell it to launch a single top and make it to be true also and call here restore state and also make it to be true okay so we can use this extension function so instead of being calling this every time whenever we want to navigate so you can just easily call this extension function here it's going to help us to handle our navigations so for this case let's navigate inside here and call our navigation host controller and call this navigate to single talk now whenever the note is clicked we want to navigate to the detail screen so that we can update our note so for this case we have to pass in the route and this route is going to go to the details screen and we have already defined our pin and basically we have to pass in the parameter so for this case the first case here we have to define the screens which we want to go so for our case we want to go to the screens the detail and we want to navigate to the name but we want to add an optional parameter so what is the parameter this parameter is going to be named as ID and for a case yeah yes I did not clicked we are going to be passing the ID of that particular note so here basically we can just refresh it as it because this are not clicked here is going to return us with a ID now here we have our home screen implemented so the next case here is to construct the another composable so this composable is going to be the bookmark so let's create here a new composable and let's pass in here our route and we can use here our screens Dot bookmark.name okay so basically here we can just pass in here the bookmark screen and similarly here we have to obtain the state as how we did earlier so let's create here a variable and call this variable to be State and we can use here now our bookmark view model and here similarly we can use the bookmark view model and pass in the reference to that function the next case here is just there on delete okay so our bookmark composable here is ready to navigate to so the last one here is we can create another composable and here we have to Define now our composable which is just the detail screen now let's pass in here the route and for case this route is going to be different from other composables because we are going to be receiving arguments and here basically what argument we are receiving is just an ID so for this case we have to modify our state here or our route in order to receive this particular so here let's pass in our screens all the detail.name and here we are going to receive the ID which we are going to provide here a like a template which is going to be replaced so this particular thing is going to be repressed whenever we navigate to this composable as here we have defined as you can see here we have defined the ID to be equal to this ID which is going to be passed when a note is clicked so this particular part here is going to be replaced with an actual ID here so now this composer will understand that I have to receive arguments so we have to tell it what argument is it receiving so for this case we have another parameter here to pass which is just the arguments and this is just going to be a list of and basically here we can have several navigation arguments so far I guess we have only one for this case but we can have five or six arguments and basically here you have to pass in the arguments as the strings or the data types that are really easily passed here so don't pass a complex object here or a total object like a knot inside here our that's why we're just passing here the ID so for this case let's just pass in here the navigation arguments and this navigation argument we have to provide their name which is just going to be the ID and here we have a place where we can Define what type of this argument so here we can say this is going to be enough type and because we are going to be receiving along so we call it nav type.long so this is just the arguments which we are going to receive now for that case we are going to receive this argument we can easily as you can see here we have a reference to the back stack entry which is just a place where we can extract that ID which you are receiving so we can just call here our backup stack entry and rename this to bug stack entry here now let's obtain the ID that is going to be passed okay so one thing which I have forgotten to be adding here so let's just keep this in a separator line because this is just an optional so sometimes we cannot pass in the ID so the default value here we want this to be negative one because a user can be navigating to this particular screen to create a new node so they don't have an existing ID so for this case we can pass in here the default value to be equal to negative one and our type is just a long so we can just pass in here the default value to be negative 1 L so for this case we can just call here our back stack entry and we can just call here our arguments and basically we want to call get along and pass in here the key to be the ID now this can be nullable and we don't want to make this ID to be nullable so if this is going to be now then we have to return here negative one which is just going to be the ID that the user is going to be creating a new node and we don't have to fetch a data to our database for this case now let's just call here our box sorry let's just call here our details stream and here for the ID we can just pass in here our ID let's pass in here the assisted Factory which is just the assisted Factory that we are going to receive here now they navigate up here so we can easily call we can call here our navigation host controller and call navigate app so we have here and navigate up which can be used to navigate back to our home screen so I think everything here is complete for our case inside our navigation so the next case is just calling this navigation and navigate to the to this particular screens okay so now here let's navigate back here and go inside our main activity this office CLS are noted this with at Android entry point that hey this is just going to be our main activity so you have to construct the the dependencies and pass it through here for the next case here we want to inject that detail the screen which we have created so for this case we can just annotate this without inject here and basically here now we can create let init variable that is going to be injected here and this is just going to be the assisted assisted the factory which is just our detailed assisted Factory and we are going to use it so one thing here which we are using here we are using the surface and basically here we are just calling three things so the next case here we want to be able to call this inside or we create a function that can be a so here basically we want to create a separate function that is going to hold up the logic of initializing our app inside the set content and not just paste or keep our code everything inside this surface here for organization purposes and the best case here their own color the content color which is just going to be the color of the content that is passed here you want to use the material theme here let's change here and use the color scheme and we want to use the on Surface because here by default it's going to use the background one so for a case let's just change this and here let's remove this okay so below here our own create we advance the literal we want to create a new composable function now let's create here icon the first case here we want to initialize our home view model and here we can use our view model composable Constructor okay the next case here is to obtain the bookmark review model so you can just call here our bookmark view model and all here the reference to be the bookmark view model and now we can use our view model composable function to construct it now the next case here is the navigation controller okay so here we have the navigation so the next case here we want to be able to track our table screens because here we have the tabs so we have the home and also we have the bookmark so here we can create an enumclass that can be used to track this type of screens so let's create a new enumclass and call this type of screen okay so here we have the home and also we have the bookmark so basically we have two tabs inside our design so you can add more tabs here whatever you wish so for this case we can track the state for this tab so we can just call this current tab and use a buy delicate method and call here our remember okay so after we import everything so here we have the state and for the first case whenever our app is launched we want to be navigated to the Home tab now here we have our state in order to display that data we can easily create a scaffold to display the bottom screens and also to pass in The Floating Action button so for this case we can just call here our scaffold so the first case here we can just pass in the bottom bar which is just the bottom above which we are going to be using as we have done inside our design so for this case we can just pass in here the Bottom bar by using the bottom up bar now the first case here we can pass in the actions and for the actions here we have two tabs which we are going to be creating so for this case we can easily create a row in order to display those tabs so for this case let's create a row and pass in here the horizontal arrangement and color arrangement Dot Center the next case we have to define those tabs so we can just call the input ships now let's provide here the parameter for selected and for selected here we can pass in our current tab if this is going to be equal to the Tab screen at home and basically here now our tab will be selected and if not then it's not going to be selected so for this case let's pass in here the on click so whenever we click this tab we want to change the current state so we can just call here the current tab to be equal to the tab screen.com whenever we click this particular tab the next case here is to navigate or call here the okay so the next case here is whenever we click this particular tab so if we are on a different sub then we can just easily call here our nav controller and call this navigate to single top because we have created this extension function inside there now whenever we call this a single top here you can Define our route and pass in this route to be screen dot home that's name in order to be able to navigate to this particular screen now this is still experimental these input shapes here we can easily just use them like that so the next case here we want to provide the label so here we can pass in the label which is just the text so for a case we can just pass in here the text and we can just call this to be home and the last thing which we can easily pass in here is just the trailing icon and here we have just to pass in the icon and we can just use the icons so here let's use the image vector okay so we're going to fix that error in a moment so now here we have our input ship and everything here is looking perfectly okay so below here let's add espesa and here basically we can just pass in a special of PDP to differentiate between these two items now the next case here is we want to so basically this is required to go up here so let's just cut this and paste it here and inside this row we can just press Ctrl C and we want to paste it here okay so these are just similar here and for the case here whenever we click this tab we want to change this state here to be not double screen here so here we have to pass in the bookmark and whenever we navigate here we can just use the bookmark dot name and for the part of label here we can just pass in the bookmark and for the icon here we can just use a bookmark icon I think so for this case here I think for the actions we have completed we can just easily collapse the actions the next case here let's define The Floating Action button because this is going to be incorporated inside our Floating Action so you can just add here The Floating Action button then call here our Floating Action button and let's pass in here the on click okay so whenever we click The Floating Action button we want to navigate to the details screen so for this case we can just call here navigate to single top and provide here our route and basically the route here is going to be to the detailed screen so for this case we're just navigating without anything so for this case we can just call our screen we can just call here screens the detail that's name to make our route here okay the next case here we have to define the icon so we can just call here our icon and pass in here the image vector okay so here we have our detailed screen not the last case here we can easily call our notes navigation inside here as the content of this particular type of composable so here we can just call our navigation okay so our note navigation here we can pass in the modifier and pass in here the modifier dot padding and then pass it here as our padding the next case here is to pass in the nav host controller and we can just call here the nav host controller so this is called the nav host okay so now everything here is complete and we have called here our not app but the next case here is to tell daggerate hey now this application you can create the containers and generate the files so for this case we can easily navigate inside here our home and one thing which we can do here is to create a new coding class or file so for this case let's create a new coding class or file and we can just call this not application so this class here is going to inherit from the application class and now here we have to tell hey Hilt you have to now start to generate this so we can just annotate this with build Android app and now it's going to know okay so I have to generate the files or the containers through this class here and we have to tell our Android iOS that we have a new application class so we have to go inside here our Android manifest and Define the name so for this case here we can pass in the Android name and we have to pass in this node application which is just the new application which we have so if everything is looking perfectly we can just try to run the application and see the changes we have made up is launched successfully and here we have our items and we can change here our data from one place to another place now the next case here we want to check here so as you can see here we have a little problem we don't have the transparency but whenever we click here we are getting the transparency of this particular thing so we have forgotten to add one thing which we're going to fix it another thing here whenever we try to write here we are not getting that uh button that we can easily click to insert our data but other things I think they are working perfectly so let's just navigate inside our details and inside here we have one thing so as you can see here we are using here the forecast container color and here we have to pass in the unfocused because here our containers can be unfocused and for this case we don't want to show any type of background so we have to add here the forecast container color this is just unfocused container color because here the forecast we have already added so let's just press Ctrl C and paste it here so this one is going to fix everything and everything is going to be looking perfectly the next case here is the button is not showing here so the button here is going to be using this type of so as you can see here we are using here is from not blank so for this case let's see investigate our detail screen and as you can see here is from not blank here we are passing here is updating node and here is updating node which in case we are not updating the note but we have to check the different thing so for this case we have to use our view model but is from not blank because when you navigate here inside our view model we were not using this variable here and this variable is going to check between these two states here and show us that if we are actually using this Insider view model so now let's try to run again application and see the changes now again our app is launched successfully now let's navigate here inside our details screen and here let's just write title and here let's just pass in title content and as you can see everything is working perfectly and when we click this button here is working perfectly let's try to add here and our data is added successfully now let's try to bookmark this item and here we have a problem inside our bookmark because it's just reloading here and for this case we are not modifying our state now let's navigate inside our details screen let's navigate inside our bookmark and investigate what we are doing wrong so after debugging here application inside our bookmark view model we are not calling this function here get nodes and for this case we will never get a bookmark the notes so we have to do here is just to call our init function inside our view module and call this get bookmark the notes inside here our bookmark new model and for this case everything is going to be fixed now there is also one thing inside here our detail view model inside here we are just changing all of this under States here but we are not changing is bookmarked so for this case whenever we save it it is always going to be false so for this case we have to check also is bookmark and we have to use the state that is bookmarked I will be changing the state but not persisting it in our database and another thing here I did not call this initialize here so also here we have to call our init function and call it initialize and basically everything will be initialized so now after this changes here let's try to click this for example and as you can see here data just added here by default now let's try to change here the bookmark directly from this here and click this button here to update it and as you can see now it's just reflected and when we go to our bookmark everything here is looking perfectly so as you can see here we have our app and I think it's looking good so if you want to improve this screen here you can easily just improve it and now whenever you click the back button we don't have the back stack problem here and then we're going to quit our application now one thing which I want to fix here is just the Dark theme the duck and the light themes which are not just correct so for this case let's just try to change this to a dark theme and for our case let's just navigate inside here our app and as you can see right now it's looking this way but it's perfect but I want to customize this or you can easily for example when you want to change it so we added colors here from our starter project so if you got this startup project from GitHub repository so you're going to get something like this so we have here the colors so we have the dark colors and also we have the light colors so for this case we can easily just navigate inside here our theme and for the part of the colors here I'm going to change this and paste here so we are overriding the primary secondary tertiary background color the surface the on Surface and surface variant and we are just using the colors which we have been defining them from here so similarly we are going to do the same for this particular light color palette here so for the light color palette here I'm going to paste this values here which we are going to override it here in order to change our color so we're just polishing here our application and make it look more beautiful so for this case let's try to rerun again and see the output which we have so feel free to customize this do whatever things which you like okay so now look at our app is very beautiful as we have changed the color and added the final polish here so basically here we can just easily navigate here from this one screen to the next screen and everything here is looking perfectly so for example here let's add here a new content okay now let's just click here and and our data here is looking perfectly if you have reached at this point congratulations on completing this tutorial so don't forget to provide a like and a subscribe if you find Value out of this content and if you want to learn more so for this case just hit that red subscribe button so until next time bye bye for now
Info
Channel: HoodLab
Views: 5,075
Rating: undefined out of 5
Keywords: kotlin, jetpack compose, android studio
Id: srp2d3_ofRU
Channel Id: undefined
Length: 157min 27sec (9447 seconds)
Published: Wed Aug 09 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.