Android Build a Clean Architecture MVVM Auth Module with Industry Level Code - Android Studio

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's up guys and welcome to this new video about building a professional authentication module in this video we are going to use mbvm clean architecture reusable composables unit tests professional programming techniques when it comes to view model and State Management also we will have a look at the performance or how we can increase the performance so that we avoid unnecessary recompositions and yeah I think it's cool to have such an authentication module which you can then take and apply to your own projects because there are a lot of Vibes out there which require login and register functionality let me quickly show you how this will look like for the login viewer we have an email address field and the password field if I enter something here then you can see we have a live form validation if I also enter a password then you can see we have no valid email as the hint for the form validation and if I enter an email address then the hint is gone and we could log in but let's navigate to the register screen green first in case we have we don't have an account yet then we have this screen with an email address input and two password fields for the password and for the password repeated here we can enter an email as well and for the passports we do checks in the background if they match to each other if they contain a special character at least one or an uppercase or a number let me also show you this if I entered the same password two times without any number then we have a hint password needs to contain at least one number then we can have a look at our passwords we can also hide them again but for the first entry we can then check what's missing and here we entered a number now and then we get another hint password needs to contain at least one special character then we can enter this special character now you can see the passports do not match and if I also enter the special character on the password field above then the hint is gone and we can click on register now we have a little uh simulated loading for the back-end check because we don't do a back-end Network request because I assume that you have your own backend solution in case you need login and register functionality this is more about the general General authentication module which you can then take and modify for your own needs or also don't modify it and just take and expand it with the network calls for example all right okay I'm here in an empty chat by composed project and the first thing I would like to do is go over our dependencies we need for this project and by the way you can find them in my githubs repository which is linked down below so you don't need to type this dependencies off here we have the dependency for dagger Hertz in our build.gradle for the project and also the dagger Hill plugin here and then in the build.gradle for the module we will have this dependencies down here in this dependency section we will need an icon which comes from this material items extended then we have the dependency for compose navigation and also the Decker Hills dependencies for the module and up here we are also have two additional plugins on the one hand kotlin caps and on the other hand the dagger Hilt plugin and what I meant by you can find them in my github's repository trust clone the initial project and you will have the same state than I have now okay I would like to start defining the different composable components like the bubbles with the animation the header the custom text Fields the authentication button and then we can use them later and just build our UI by putting them together like we want and for that we will go to our root package and we will create a new package called presentation and inside this presentation package we can then create another package called components when we apply the clean architecture principles we normally have different features slash modules and inside this features slash modules we have a presentation layer for UI related step stuff the domain layer for business logic and the data layer for data related stuff like Network requests or database requests or something like this and here in this project in this application we are in the off module we are already in the module and this is why the presentation domain and data layer are right below the root module here if your application gets bigger then this off module which is now our root package will be one package below the root package if in case your application is bigger let's also create the domain and the data package even though we don't need it yet but we can then see how this would look like later and inside this components package I would then like to start with our authentication button by the way we could also take this UI Auto generated package with the theme the colors shape and so on and put them in the presentation package but I think it's fine to leave them where they are and also what I need to mention is that I added some colors here we don't need all the colors but this is my default color palette which I always add to my projects and um well they are also included in the initial project so you don't need to type them off in the components package we will create then our builds composable which will be an out partner and this will be a kotlin file and composable and since this partner only differs by the text for the login and for the register screen we will make this a reusable composable of course this partner will have a text of type string a background color of type color the compose color the content color of type color if it's enabled of type Boolean which is true by default and then we also have a Lambda functioner on button click and this won't take anything and also does not return anything then we have also it's loading because when we are currently loading then we want to show a circular progress indicator instead of the button text and then we have also a modifier which we set to the default modifier so we can modify this off button from the outside then we will Define our partner for the modifier we will pass the past modifier and let's import this partner then for the on click methods we simply call this on button click and then we have also a shape for this partner which will be a rounded Corner shape of 25 PP for the colors we will say button defaults dot button colors we will pass our background color the content color is equal to content color and also this disabled background color will be set to background color because the button will be disabled if the form validation says we have an invalid input then we will disable this partner but I think it's okay to keep the original background color and just disable the clicks and we will also have the disabled content color set to a Content color then we have enabled is equal to the Past Boolean enabled like this and then we can open this button scope or better save it's a row scope and then we will say if it's loading when we are currently loading waiting for the result from the back end then we will show a circular progress indicator the color will be set to White and the modifier will be set to modifier dot size 20 DP or let's don't set it to White let's set it to our content color because this already works for our text content then it should also work for the circular progress indicator in the else case we want to show the button text we will say text and the text is equal to our past text from above let's import this text compostable and the style will be set to material beam Dodge typography dot body one we can also have a look at how this button will look like with a preview I think this is really useful because then you don't need to start building the actual screens where you invoke them the app and have a look at it there so we will say add preview show background to true and then we will Define our them off Butner preview like this and here we invoke our off partner for the text we simply say log in for the background color we say Orange and for the content color we will set white button click can be left empty is loading is set to false and then we can go to split above and click build and refresh and then we should see our authentication button well okay this looks a little bit uh too small we have the possibility to change this with the modifier we will simply say modifier film x width and let's decrease this a little bit and yeah I think this partner looks fine we can also check how this would look like with the loading indicator if we said it's loading to true and then you can see okay well we don't have animations here but you can see this little white dots which indicates that the loading indicator starts with its animation there okay all right then we can close this we can also close all the previously opened files and go to our components package again and we will create our next composable this will be called text entry module this will be of course the file compostable text entry module and here we will need a bunch of parameters because such a text entry module will be a text fields and the description above we will make this one composable so we can just enter them later when we are in our login or register view but therefore we need a lot of parameters first the description of type string then we also need a hint of type string an image Vector of Type image Vector then the text value of the text field of type string then we will also provide the possibility to pass a keyboard type we will set this to keyboard type dot ASCII by default but in case you want to pass um some other keyboard type then you have the possibility to do this but we have also a visual transformation which we will set to visualtransformation.non by default but later for the password fields we need a password visual transformational so that the password is hidden behind this black dots then we will also have a text color of type color then a cursor color of type color you see I make this really General so that you can really use this and apply all the things you want later then we have an on value changed Lambda function which takes this which provides us a string and returns nothing and we have a trailing icon of Type image Vector which is optional because not all our input Fields have trailing icons only the password input Fields will have a trailing item where we can then click on to show or to make the password visible then we have and on trailing I can click which is a Lambda functional that does not take anything and does not return anything and it is also optional and the last thing is the modifier which we will set to the default modifier to allow us to modify this text entry module from the outside in this function block we will first start with a column this column takes our past modifier from above and let's also import this like this and then we can open the column scope and first we will have a text for the description here we will pass our description let's import the text if composable the color will be set to our text color and the style will be material theme dot typography dot body tool so this will be our description and I'm not sure why we have an error here is this the wrong color oh yeah we have the wrong color imported um let's use the um compose color then the arrow is gone and then below this text we will have the text field for the modifier we will say multiplier.filmx with we will have a little padding to the top of 3dp let's also import steep here then we have a border of 0.5 DP and our text color and a rounded Corner shape of 25 DP then we have the heights of 50 DB and a shadow of 3dp rounded Corner shape 25 DP the next thing is our value so the actual text input here we will simply pass our text value the colors will be a text Fields defaults dot text field colors for the background color we will pass white here or the cursor color we will pass our cursor color and this hard coated white color is not that General but I think text Fields should always be a kind of wide and then we have a focused indicator color will be set to color Dodge transparent so that we don't see anything there and the unfocused indicator color is also set to color dot transparent then we can pass to the on value change parameter our on value change has a function from above and the shape will be set to rounded Corner shape 25 DP then we will also set the single line to true and the leading icon will be an icon and for the image Vector we pass the image vector and let's also import icon let's rename this to a leading icon this is a little bit better and then image Vector then we have a Content description I was just set this to another The Tint will be our cursor color and the next parameter will be our training icon and here we need to check if the trailing icon is actually null or not we will say it's trailing icon is not equal to null then we can say icon for the image Vector we will pass our trailing icon the content description will be set to null again the tint will be set to our cursor color and here we say modifier is equal to modifier dots clickable here we need to check if our ontrailing icon clicked Lambda function is not equal to null if this is the case then we can invoke this on trailing I can click function the next thing will be our placeholder here we will pass the text and for the texts the text we will pass the hint this dial will be set to material beam dot typography dot body tool and text align will be set to text the line.start but I don't think we actually need this uh yeah let's just remove it and then we will also have a text style for that we will pass material theme Dodge typography.body tool and then we have the keyboard options there we will pass our keyboard options and the keyboards type will be set to our keyboards type and the last parameter before we have finished this composible is our visual transformation where we simply pass the visual transformation from above all right okay this is a huge text field and I would suggest that we have a look at the preview but I think I will just copy and paste this because I don't want to bother you with invoking this composable inside the preview but I think this looks really cool of course this I I can at the end as the trailing icon does not make sense for an email address field and yeah but I think the styling looks pretty cool we can also enter a value here text input like this and then we can say for the visual transformation we want to have a password research transformation and then we can have a look if this also works and yeah I think this looks also pretty cool so we can continue with our next components the next component will be our bubble animation for the three Bubbles at the bottom which go from left to right and uh kind of animated and gives a nice feeling and here we can um we don't have a class we have a composable bubble animation here we have two colors the bubble color one because this will be a gradient linear gradient where we need two colors we have the button color One Imports the compose color and then we have the button color add a bubble color tool which is also of type color and also a modifier again to allow us to modify this from the outsides first we will have a well in minutes and transitioner is equal to remember infinite transitioner then we will have a box where we pass our modifier and open this box score here we will have now a little bit of boilerplate code maybe there's also a more General way to create this but this bubble animation is anyway only a little bit of a play around so we will first start with valid x value by infinite transitioner.animate floats the initial value will be set to 100f the Target value to 100 1340 F and the animation spec will be infinix repeatable the animation will be set to Twin the duration will be 7 Seconds we have a linear easing and the repeat mode will be repeat mode dot reverse then we also need to import the missing dependency and the arrow scan so this is the x value for the first animatable Circle so the horizontal way and we also need a vertical way here we can say well y value by infinite transitioner dot animate float for the initial value we will say 100 f for the Target value 700 F the animation spec will be set to infinite repeatable again the animation duration will be all the animation will be a tween with six seconds duration again we have linear easing and the repeat mode will be again set to repeat mode dot reverse and here we also need to insert the parameter name and this is the animation definition for one bubble we can just copy and paste it down below for the second and for the third part the bubble and change the parameters a little bit here we will say x value 2 y value 2 here we will swap this um two values so that the bubble different from each other here we will say um 400 F here um 200 f increased the duration to 7 seconds and here to 8 seconds and then this second button behaves a little bit different we can copy and paste this again for the third bubble and again this is only a little bit of a play around you can try to make this more responsive without hard-coded values or also just leave it completely this is not necessary here I also just tried around a little bit with it here we will say 1000 F and here 400 f and change the duration to 7.5 seconds here also change it to 150 F the target value will be set to 600 F and we will also decrease the duration to 6 seconds then we can use make use of the canvas for the modifier we will pass multiplier dot filmex size so the canvas will expand to the box size and then we can draw our circles here we will say draw a circle for the brush we will say brush dot linear gradient we will pass a list of colors the bubble color one bubble color two then the starts will be set to offset x value minus 90 and Y value and the end will be set to offset X Value Plus 90 and the Y value then we will also pass the radius of 100 F the center will be set to offset and for the x value we will pass x value and for the Y value we will pass the Y value then we can just copy and paste this two more times and change the values here the x value 2 is used for the second bubble and also of course the Y value 2 and here for the third bubble we will use the x value 3 and the Y value 3 also need to change this above here here we will also use the Y value 3 and the x value of 3 and we will make one bubble a little bit smaller than the others and yeah then we are good to go to try this out in the preview let's add a preview show background is equal to true composable bubble animation preview in here we will invoke our bubble animation for the bubble color one we will pass orange and for the bubble color tool we will pass gray and then we also need to define a modifier the modifier will build a Max width and for their height we will say 250 DP then we can go to splits and there we can have a look render issues okay let's try it again and here you can see the preview um does not show animations but we can click on this run preview here and open the app list and then you can see the animation kind of works and we have smooth animatable bubbles here and we are feel free to adjust them to your own needs or just leave them out of your application I think they are a really cool play around okay all right the next composable component will be our header background so the half circle at the top of the app we will call this header background this will be a composable this will be a rather short composable at the background which takes the top color of type color and which compose UI Graphics color the bottom color of the same type then we will also have the modifier which will be set to the default modifier and then we have a color list is equal to remember and here we will say list of top color and bottom color and of course we could have used this color list for our bubble animations as well so we would have only one Central list but well this is okay the canvas then takes the modifier and in here we will draw a circle we draw a circle the radius will be set to size dot width the center will be set to offset Center dot X and minus size dot width divided by 1.2 F let's also import offset and we will also have a brush which will be a linear gradient it takes our color list and the end will be set to offset we will pass center.x plus 500 F and 0f for the Y value so what this does and this parameters here um do um they kind of take the circle we Define here and move it really above our apps Vision the scope and then we will only see part of the circle the bottom part of the circle and this will gives us this header background we can have a look at the preview show background to true then we will have a composable background add a preview here we will invoke our background header a header backgrounds uh well let's swap this name for the top color we will pass orange for the bottom color we will pass whites gray orange this is what we also use in the login and register screen later then we will also have a modifier here we will say filmex size and then I think we should already see the right header let's click on build and refresh in our preview and yeah then you can see we have this header background and we should also change these names to left and right color because first I was using a gradient from the top to the bottom and not from the left to the right so um let's change this to a left color and this name to right color then it's more understandable all right okay this was it for our composable components for the register and login screen now we will go to our domain layer where we will provide the business Logic for validating the login and register inputs so that we can use this business logic to determine what we should actually show to the user we will also validate later that our business logic actually works properly with unit tests in our domain package we can create another package called Model where our business models belong to here we will create an enumclass called login inputs validation type this enumclass is kind of a language for the view model later because our business logic will return such a login validation input type and then the viewmodel can determine what should be shown how to update the state depending on this type and as I said this type is kind of a language which tells us that we have for example an empty field in our login input because we don't want to allow the user to press or log in if there's at least one empty field then we also want to avoid clicking login if the input of the email text field does not contain an email or we can also Express with this enum class language that the input is actually valid then we can go to our domain package and create another package called use case and in this use case package we can put use cases which represents our business Logic the first use case will be validate login input use case then we can override its operator function because we can then invoke this use case later in a more convenient way this will take an email of type string and the passwords of type string and it will return a login input validation type in here we can then first check if email dot is empty or passwords dot is empty if this is the case we can return login input validation type empty fields then we will also check if the add sign is not in the email string then we can return login input validation type dot no email and I know this check is not enough to stay if this is actually a valid email or not we could also check with a regular expression for example if there's only one at sign but then the user can also type in invalid emails well this should probably be the principle of this use case with this enumclass you can expand this and use a regular expression for that and for now we will only use regular Expressions later for our register input to check if we actually have an uppercase a special character and so on because we can't really prevent the user from putting in something that does not make sense for an email um yeah and if we are here in this line we can then return a login input the validation type dot valid and now we are good to go to write three or four unit tests for this use case and I like this about use cases because they can really be tested in isolation and we don't need to provide fake or mock implementations or something like this and yeah this makes them really powerful in my opinion of course you shouldn't write a use case only for sorting a list because this is kind of a one-liner but if you have more complex business logic then they are really really cool in my opinion you will see this is even more powerful when we have the valid register input use case because there we don't have only two if checks we need to check for special character we need to check for uppercase for numbers if the passwords actually match empty fields and so on and there you will see how cool this use case is it ah and how easy we can test them for testing we first need to add a dependency in our Builder Gradle for the module and we can right insert it here below this test implementation we will use the Google troop Library which is a powerful testing library and I think we can also just remove this J unit for DOT 12 and then we can click on sync now after the sync was successful we can go to our test module go to our off module here and we will have the same package structure in our test module like we have in our production module so we will create a domain package and use case and in this use case package we will then create our validates login input use case tests you can also select the more convenient way by going to the use case click on generate test select junit 4 press OK and then you could also press OK here and then the test class will be generated automatically but I think it's cool to show where the test is actually located because it's in this test module and not in the Android test because we will do unit tests here and in this module the Android test module there's some kind of integration tests where we actually need their Androids operation system and for unit tests in this module we only need the jvm so we can go to our validates login input use case test first we need a reference to our use case we want to test private well validates login input use case and then we can straight initialize it here and and then we can start with the test annotation and then we can write our test functions the first thing we want to test is if the email or the password is actually empty then we should get the login input validation type dot empty field as a return so we can call or we can name this test like this with this backticks test empty field returns validation type empty fields and then we can say well result is equal to our validation our validate login input use case and for the email we will pass an empty string and for the passwords we will pass something else just passwords or something like this so that one field is actually empty then we can say assert that the result dots okay first we need to import a third from the truth Library is equal to login input validation type dot empty fields and then we can click on this play sign and run the test and have a look at if it actually passes okay all right this looks good the test actually passed and I think we should also rename this and remove this typo return validation type empty field like this this is uh for the sake of grammar and then we can copy and paste this and maybe you also want to test if the password is empty and the email contains the value but I think this test case is enough well let's write both test cases this goes really quick test empty email field return and here test empty passwords fields and here we will pass an email with ADD assign and we will leave the password empty and then we should also get this empty field returns and here execute all tests and we can see both of them passed and now we can check on the email sign let's copy and paste this one more time and here we will then say test no email return validation type no email and then we will just remove this add sign and for the password we will simply press password and here we also need to change the validation type and then we can try this out and have a look and now you can see also this test case actually passes the last thing we want to test is if the input is actually valid that we also get a valid response so we can rename this to test everything is correct turn validation type valid then we enter a valid email and a valid export and here we get done the result valid and we can check on this run this test case and then you can see also this one passes and at the end if you want to check if everything works then you can click on this run sign and click on run and then you can see all four test cases actually passed and maybe you're asking yourself why this is even necessary because this use case is really easy we don't even need to test it but well I'm sometimes in the future maybe you change your check validation login input use case and then you will also want to be sure that your changes didn't affect the previous logic and then you can just click on run again and if all the test cases passes then you can see or you can be sure that your changes didn't cause any errors also and of course sometimes the business logic is even more complex which makes testing even more important and you will see that the validate register input use case is also more complex one which of course requires more test cases but after that we can be sure that this use case actually works let's go to our model package and create a new enumclass for register input validation type like we had in the for the login input validation type here we had only three cases but for the register inputs validation type we now have more things to consider we have the empty field case the no email case then the passwords do not match case as words uppercase missing password number missing passwords special jar missing passwords two shorts and the last case is valid now we can go to our use case package create a new use case this will be called validates register input use case this will be a class and we will again overwrite the operator function invoke and here we have three parameters the email of type string the password of title string and the passwords repeated of type string as well and the return type will be register input validation type and the first thing we want to check is if email dot is empty or passwords.smt or passwords repeated dot is empty so nothing new here we again return register input validation type empty fields and also the second check is nothing new here we will again check for the add sign if at is not in email then we will return register input validation type no email but now things get a little bit more interesting we will first check if the passwords is not equal to passwords repeated then we will return register validate a input validation type dot passwords do not match the next thing we want to check is if passwords.count is less than 8 then we will return register input validation type passwords to shards the next check if passwords contains numbers like this would be really cool to use but we don't have this contains number functions I would like to create an extension function of string which can then be invoked on this password string for that I would go to our root package and create a new package called util because I think this does not belong to our business logic such a string extensioner can be used everywhere so if you have a project a bigger project with more modules then you maybe want to use this string extension everywhere so we go to our util package create a new file string extensioner and in here we will have a functional string that contains numbers this is how we do this in kotlin and this will return a Boolean then first we will Define a regular expression this can be done with the regex M Class here we will have a DOT for um any kind of character and this Asterix says that we can have any amount of any kind of characters then we check on a number so one number is enough so we apply a plus sign here and after this number we again have the dots and the aster is and this regular expression now means that we can have any amount of any kind of characters then we need one number and after this number we can again have any characters so this checks or this expresses that we have in the string at least one number and then we will return regex dot matches and we will simply pass this with which is the current string on which we invoke this contains number function we can also already Define the other extension functions we need later for example contains uppercase functioner which also Returns the Boolean here we will again have a regex which we can Define like this but we again have any kind of characters and then we have a to set so uppercase letter and a plus sign that means at least one and after that again a DOT and the asterisks for any kind of character then again return regex Dodge matches and we will pass this after that we have a string dot contains a special jar which once again a Boolean the regex is now regex and first we have our dots with the asterisk and then we have this negation a to set no like like this a to sets for the uppercase and a to set for the lowercase and this four number and after that we have again um the asterisk with the Dodge okay what this means here is that this are all characters from A to Z upper or lowercase and also all numbers and this negation means that it is some kind of other character which is not in which is not in this range here and this plus says that we have at least one of them so this expresses that we have at least one special character then we can say return regex dot matches and we will pass this and now we could of course start using this extension functions here but how do you want to know if this is actually working I don't want to open the app later 10 or 20 times and try all the possibilities for the passport inputs and for that we can again just Define test cases which then shows or validate the correct behavior for that we go to string extension class click on generates tests we select junit 4 press on OK and I'm not pretty sure why we don't have the automatic suggestion for the destination here okay this doesn't matter we can just go here to our test module go to our root package there create another package as a quick reminder we need the same package structure or the same package structure is a good practice here and in this YouTube package we create then string extensioner tests and we can start with our test cases the first test will be functional test string contains no number returns false then check for it like this and then we can say well result is equal to the string no number for example then we check on contains number like this and why don't we have this oh well okay that was done and these are extension functions and we don't need a class for that just remove this class and put it like this and then we can go to our test again and this this contains numbers is also misleading um function name sorry we will call this contains number and then we will check asserts that result is false and for that we need to import the group so that library then we can click on run for this test case and check if everything works and okay well we need to um uncomment this first go to our test pack and click on run again uh okay well let's just return a register dot valid we need to return this anyway at the end go to back to our test cases and then press on play and then we can see the test passes and then we can continue checking on other functionality for that we can copy this test case and paste it test string contains a number returns true when checked for it here we will simply insert a file and we need to check this change this to is true and I won't press play after each test case I will Define now all test cases and at the end we let them run all at once the next test will be a test string contains no uppercase returns alts when checked for it so we will have a string without an uppercase then we will invoke contains uppercase and this should return false then we can again copy and paste this and oops this time we have contains an uppercase returns true and check for it and we can just leave it like this change the functional contains uppercase and this should result in true and now I'm going to paste rest of the test cases because I think it that does not make that much sense if I type this off and copy and paste and all that stuff the nice test cases are test string contains no special character returns false when checked for its um here this string is checked and here we have contains a special character returns droop and checkpoint here we have the special character and now we can go to the top and run all the test cases and check if they all pass and now they are all passed and we can be pretty sure that everything works maybe you want to check some edge cases or something like this for me this is fine for now and then we can close this test class close also the string extension class and we can continue with our validate register input use case okay we first can uncomment this and imports contains number like this and if the password does not contain a number we negate this here we can return register input validation type dot no number or number missing like this and then the next case if password does not contains an uppercase then we can return register input validation type Dot missing uppercase and let's also remove this typo contains uppercase like this and the last check we want to do is if the password does not contain a special character then we want to return register input validation type dot special character missing and now you can see this use case is kind of big and we also want to check if this use case is actually working so let's go to the class click on generate test select junit 4 and then we can press on ok now we get the automatic destination suggestion I don't know why this didn't work earlier we can press on OK and then it's automatically generates us this class in the right direction directory here in this use case package and now we can start to define the different test cases for this validate register input use case this time I will just copy and paste them because I think this is always kind of similar to the other test cases definition but I will go quickly over them so that you can see what's currently going on and what's actually tested so first of all we need to import this validate register input use case and I think I made a typo before yeah I I made a typo again and let's kind of change attach this here like this and we also have the wrong assert Library here we can import tests and then import a search from truth and imports the register input validation type and then we can quickly go over the test cases with such more complex things to test I like to start with a test where everything is the way it supposed to be like we have a valid email a valid password and also a whether it's repeated password and then we should get valid as the result and from this test case I derived then other test cases where I make small changes and test the different possibilities here for example here test register input with no email gives correct return type so I I just removed the add sign here and changed this to no email then here test register input with not matching passwords I left the email here like it was and then I just inserted this little character so that the passwords do not match anymore change this here and here test register input with uppercase missing and yeah here I change the passwords and also made sure that the repeated password is the same but without an uppercase change the input validation type yeah I think you get what I mean here also check for numbers special character and if the password was two shots and then we can click on run and check if everything works and again we have oh this does not look that good okay because I made this uh typo change for the use case um well I have to look into this I'm not really sure what was causing this I just rebuilt a project and then everything worked so if you face the same Arrow then just reboot the project and it should be fine I also changed this um uppercase as to a lowercase as in this use and then we can um now run our test cases and they all pass and our use case for validating the register input seems to work fine all right okay I think this was it for the business logic now we can start to build our viewmodel let's close this test and go to our presentation package and also let's collapse this test module in the presentation package we will create another package called um state and in this state package we will first create a data class called login State because our viewmodeler will make use of this log in state class to represent the current state which can then be observed from our compostable to show the corresponding UI elements let's select data class and press enter and this login state will have multiple values we will have an email input this is a string and this string is empty by default then we have a password inputs of type string which is also empty by default then we will have a Boolean which indicates if the input is actually valid this is set to false by default then we have a well is passwords shown which is also Boolean if the user clicks on the icon on the trailing icon on the eye then the password can get visible or it can be hidden and this a state bar is indicating this then we will set this also to false by default and then the next value will be well error message input of type string which is optional and now by default because we don't want to start straight away with a hint for the user that the fields are empty we will only start this when the user enters the first character then we have the value is loading later for the simulated Network request to show the circular progress indicator it's a Boolean set to false by default and then we have have a well is successfully locked in which is also a Boolean and Falls by default and we have a error message login process of pipe string which is optional and null by default and here the difference between this error message and this error message is that this one is indicating an error and potential a potential error which comes from the network request if some error occurs some exception is thrown also and this error message is is just for the hint to show the user that we have an empty field left or that's the email Fields has not a valid email or something like this yeah this is the difference of pen tool then we can go to our presentation package create a new package called viewmodel in this package we can create a new kotlin class called login view model and bodegaert later we need to annotate this with ADD Hilt view monitor in case you don't know what daggerhill is it's a dependency injection framework which keeps your code very clean because you don't need to take care of the dependencies you just need to Define them in a central place and we will do this setup later but right now we will just make use of this annotation and also the check annotation which we need for dependencies and here we can say private well validate login input use case and later dagger Hill will take care to provide us this use case and yeah but you will see how we can set up this later then we have a login state by mutable states of login state uh let's import this and also the get and the set values for the mutable state or like this we will make this a private set so that we can only modify this login States inside our viewmodel then we have a bunch of functions we will have a function on email input change new value will be a string and then we will say login States is equal to login state dot copy and we will say email input is equal to our new value this copy will re-initialize this login State and keeps all the different properties and only changes this email input and this new this re-initialization costs then the UI to updates if we would only say something like this login state DOT email input is equal to new value where this email input is the value anyway so we couldn't change this but if this would be a bar and we could change it this would not trigger an update of the UI later but we can achieve this with this copy functioner then we have the next functioner on passwords input change which also takes a new value of type string here we can say login States is equal to a login state DOT copy password input is equal to new value the next function of functional on toggle visual transformation for our password to hide it or to make it visible to the user login state is equal to login state DOT copy and here we say is password shown is equal to not login state DOT is password shown so we kind of toggle this and after that we will have a private functioner check input validation and I always like to start with the state bars in the view model then the public functions and then the private functions so it's always structured and is gives a cool overview where different things are we will have a well validation results is equal to validate login input use case and we already know that this use case should work because we actually tested it then we say login state DOT email inputs and login States dot password input for their two parameters and after that we can call this check input validation from our own password input change and from our on email input change functioner and now we can then process input validation type and we will pass our validation result so private functional process input validation type type login input validation type and the reason why I put this in uh or not not protected is private and the reason why I made a separate function for processing this input validation type is because of the separation of concerns this function has the responsibility to check the input validation type therefore it's uses the use case to get this validation type and this function's responsibility is to process this input validation type so both functions are really clear and only have one responsibility and this keeps your code clean you should always prefer small functions with single responsibilities over two complex functions and also it's a good practice to put the functions that get invoked below the functions that invoke them so we have this for this check input validation here this function is defined below these two functions and also this function here which gets invoked here is defined below this function here this here would not be that good practice in terms of um readability of course this is not always realizable but um yeah um if possible you should always do this then we say login state is equal to when type log in input validation type dots empty fields then we say login state dot copy error message input is equal to empty Fields left and we also need to say is input valid to false because imagine if the is input valid is set to true if everything works and the user starts to delete characters then um we have for example again an empty field and we should always then set this input value to false again and don't forget this after that we have the case login inputs validation type no email here we say login state DOT copy error message input is equal to no valid email and again is input valid is set to false and if we have the case if it's valid then we say login state dot copy error message input is set to null and is input valid is set to true the last functioner we want to Define is the function on login click we leave this empty for now and take care of this later but we can already invoke it stem from the UI later okay all right this was it for the login view model the next view model we want to Define is our register viewmodeler register viewmodeler inside our new model package here we can again make the hilt view model annotation say inject Constructor privateware register input oh no register command input use case like this and then we have the view model inheritance let me check if I also have this oh no I forgot it here view model and then we can start with our state again for the register new modeler we have another state data class register state will be a data class here we will have a well email input of type string which is empty by default the passwords inputs of type string empty by default where passwords repeated inputs of type string MP by defaults well is input valid again well I think it would be faster if we copied the login State and adjusted it a little bit never mind well it's passwords shown of type Boolean is equal to false well is passwords repeated shown of type Boolean which is false by default um where error well this this can be copied now the last four like this well error message input is loading is successfully registered and error message register process like this this will be our register State we can close this go back to our viewmodel here we can say VA register states by mutable State off and pass the default implementation of the register State let's import this get and Setter for the delegate mutable state of and we will make this a private set so that we can only modify it within this register view model all right okay then we can go to our login view model and we can copy and paste this functions because they don't really differ from each other we will have on email input change and then we say register state is equal to registerstate.copy here we have the same register State it's equal to registerstate dot copy then we need another password functional on passwords repeated inputs change you will change this to password repeated input and here we will also have on toggle a visual transformation passwords and on toggle visual transformation as well repeated and we again need to change this to register States registerstates dot copy here again here we will say registerstates dot copy is password repeated shown and then we say register States Dot this password repeated shown and let me put this in a separate line so that it's more readable okay all right then we also need this check input validation functional I think we can also take this from our viewmodeler and after that we need to Define our own but now we can just copy the logic here we will take the register State and make it like this and for the third parameter we need the is no s word repeated input and we also need to change this to validate register input use case and here we can also take this function name because we also need to process the inputs validation type here type will be register input validation [Music] type and this will be a function of course let's import this open the function scope and then we can start processing this type and I decided to copy and paste this functional because we have a lot of different cases here which needs to be processed here we have the empty field no email password to short passwords do not match password uppercase missing and I think this would be not that practical if I type this off and only the the string changes here you could also move this logic of string determination out and keep this function a little bit more small but um well this is up to you this can be of course made cleaner because it's only about the string which changes here and okay um this case is a little bit different but um yeah if you want to move the logic for determine the string out of this function then you can of course do this with a separate private function I think this is uh still fine so and the function is not too long still has its own responsibility and it's still also readable so for me it's fine and the last thing we want to do here before we continue and start with building our UI setting up back ahead and so is another public functional function on register click which will be also empty for now we will Define this later there we will do a little simulation where we simulate a back-end call but for now it's only divined without any logic all right okay now we can start building our UI first I would like to take care of the navigation we can put this in the util package because normally the navigation logic is not only in the auth module but in the general app or on the core module or something like this so I will put this in the user package called navigation this will be a file composable navigation and first we will have the nav controller nav controller is equal to remember nav controller and then we will have then we will have a nap host which takes our nav controller and we first need to define a start destination and for all the different destinations we have we can create a sealed glass sealed glass screen rods and this will take over route of type string and we will have an object login screen which inherits from screen routes we will pass for the route login screen then we will have an object register screen which also inherits from screen routes here we will say register screen and also let's change this to underscore and we will have an object Final Destination which we leads the user to when the login or register was successful of course in a real world application then you would provide some kind of destination where the user should be directed if the login or register was successful Final Destination like this and of course needs to inherit from screen routes and the start destination will be screen routes dot login screen dot route and then we can open this to define the department routes we both need our compostables which we can invoke if a specific route occurs so we will go to our presentation package create a new file called login screen composable login screen and this will take two Lambda functions on login success navigation which does not take anything and does not return anything on navigates to register screen also does not take anything and does not return anything and a login view model which is a hilt view model like this and we don't need to pass the nav controller here the login screen does not need to know about the nav controller we can completely put the logic of navigational inside our navigation and compostable let's see how this works here we can Define the composable for the screen routes dot login screen dot route and we will invoke the login screen then and for the on login let's import the login screen first this one on login success navigation we will pass navcontroller DOT navigate screenroads dot Final Destination dot route and then we will also say pop up to null or zero because we don't want the user to be able to navigate back after the login was successful and with this approach also the login screen does not need to know about the nav controller we do the navigation really only in this navigation composable with this with the help of the Slumber functions then we also have the on navigates to register screen here we will say navcontroller dot navigate screenroads.registerscreen.rout and also we say pop-up tool now or zero because otherwise the user can always toggle between login and register screen and then the backstack gets increased time the user does such a navigation then we can do the same for our register screen we will say register screen in our presentation package composable register screen and I think we can copy from the login screen this re-parameters or Lambda functions here we will say on register success navigation or navigate to a login screen and here we have of course the register new model of type register view model which is also a health view model and then we can go back to our navigation and here we Define the composable for the screen routes dot register screen dot route register screen and put this one here and for this two Lambda functions we then say netcontroller dot navigates green rods dot Final Destination dot routes and we will say pop up to null and we can then copy this and paste it down here on navigate to login screen and here we will change this to login screen as well and I think we need a parenthesis like this the last screen we need to Define is our final destination screen let's go to our presentation package create a file final this T Nation will be a composable of course Final Destination this won't take any parameters here we will have a simple box with a modifier which is equal to modifier let's import box remove this wrong import of the modifier use the compose one and we will fill the max size set the content alignments to alignments.center open the box scope put in a simple text import this the style will be material theme dot typography dot body one for example and the text will be congratulations like this then we can close this Final Destination screen we don't need it anymore and Define the composable here in our navigation or screen routes final destination.route and here we simply say Final Destination like this and this was it for our navigation we can also close this screen or this composable go to our main activity remove all this default stuff and simply say navigational like this all right we are almost ready to start with our login and register screen and put everything together let's set up Lego held first and then we can start with the final part of this video for the setup of dagger Hilt we need to go to our root package and create an application class we will call this all application make this inherit from application and we need to annotate this within ads Hilt Android app then in our main activity we need to annotate this with ads Hills no Android entry points and in our manifests we need to define the application our off application then we can close the manifests also close the main activity and now we need to define the different dependencies for degahertz which are right now only the two use cases we can create a new package from our root package called di we will call this package app module make this an object this will be a module so we annotate this with ADD module at install in Signal component double double colon class and here we can then provide with this different annotations and our dependencies first we will say add provides at Singleton functional provides validates login inputs use case this will return a validate login input use case and we can simply say return validate login input use case then we can copy this for our register input use case validates register input use case again and down here again and this was it for the dagger Hill setup later when we simulate the back end call then we will create a repository interface and class and then we need to provide this here as well but for now this is fine and we can try to start the app and have a look if everything is set up and we don't have any builds or compiler errors for that select app up here if you have still the test case for the start and we can select a pixel device and start the application and have a look if everything works alright okay the app starts this is fine we can now start to Define our login screen and put our different composables together let's close this emulator and go to login screen here we will start with a box and this box takes the modifier and let's do the Imports the compose modifier the Box and this modifier will fill the max size and the background will be set to whites then we can open the box scope inside this box we will have another box with a modifier and this modifier will build a mix with and the heights will be 120 DP so this will be our for our header background and we will set the content alignments to alignments.center let's open this box scope then we will have our header background composable for the left color we will have orange for the right color we will have white gray orange then we will have a modifier and this modifier will simply fill the max size below the center background we will have a text composable the text will be login let's rearrange this a little bit and for the style we will have material theme typography dot H4 the color will be set to wires different ways will be set to front rates dot semi boards and then we can just have a look but starting the application again we could also provide a preview here but you can see we have this header background and also the text for the login one thing I would also like to do is to go to the main activity and here we will set window dot status barcolor to gray.2 uh GB and the window dot navigation bar color to gray.2 RGB as well then we can start this again and have a look what this did and now you can see the navigation and the status bar color is gray I think this looks a little bit better um instead of the default purple or whatever color this is then we can close the main activity and continue in our login screen now for the main container where the email and the passable text field is and also their authentication partner I would like to create a container which takes a lot of Lambda functions which return the necessary information to increase the performance we can decrease with this principle the recompositions I already made a video about that to increase performance in compose and exactly this principle is applied here in case you missed this or you don't know about this principle make sure you check this video above and now we can define a composer book called login container normally you would assume that we that we as the parameter email value like this but um this would not make that much sense for this performance Improvement because we would need to reach the state here in in case we call this login container we would say something like login viewmodel.loginstates dot email input and then we would read the state here and we don't want to read the state in the whole login screen for um performance reasons we want to reach the state in this login container and we can achieve this by making this a Lambda function which returns a string and then we can put this inside a Lambda functioner reach the state there it's a red inside this Lambda function and here we can for example say text email value like this and then we reach the state here in this login container well I won't dive too deep into performance and Jetpack compose um make sure you check this video out which I already made there I go more into detail okay let's remove this and also remove this and continue with our parameter definition we will have a password value which will be also a Lambda functioner which returns a string then we have the if the button enables Lambda functional Boolean on email changed which will be an under function as well which provides a string and returns nothing on password changed provides a string returns nothing and don't forget the double colon here then we have a functioner on Butner make which does not take and does not return anything let's call this on login button click for better readability the next parameter will be is passwords shown which does not take anything and Returns the Boolean on trailing passwords I can click does not take anything and does not return anything then the arrow hint which returns an optional spring then is loading which Returns the Boolean and finally a modifier which allows us to modify this login container from the outsides in this login container we will have a column and we will pass the modifier let's also import column the vertical Arrangement will be set to Arrangement dot Space by 15 DP then you can open the column scope and start with our text entry module the compostable we defined earlier and for the modifier we will pass modifier.filmax with the text value no the description will be set to email address the hint will be set to key apps at gmail oh at gmail.com you could of course also work with screen resources for different languages but well I won't do this here then for the value we will say email value and invoke this functional to read from the state the text color will be set to gray the cursor color will be set to Orange Let's import this gray color on value changed is equal to on email changed the trailing icon will be set to null for the email field and on trailing icon click can be set to null as well and then we still have a missing parameter let's see which one ah yeah we need to provide the leading icon which comes from icons dot default dot email and then we have our email address text entry module we can just copy and paste this then for the password Here we will say passwords for the hint we will say enter passwords we will reach from the password value state gray orange is fine for the on value change functioner we pass on password change the trailing icon in this case is um icons dot default dot remove red eye and the untrailing icon click will be also set and here we invoke on trailing password I can click and for the needing icon we say icons dot default dot um what's it for PN VPN key I think okay the visual transformation depends on if is password shown read the state from here then we have a visual transformation none in the earth's case we will have a password visual transformation like this and the last thing we want to Define is the keyboard type here we say keyboards type dot password oh I forgot to invoke this function here make sure you add this parentheses to actually invoke this function below this module we will have a column with a modifier this modifier will build a mix with and the vertical Arrangement will be set to Arrangement dot Space by 5p this will be for our auth partner and at the bottom below the off button the hint what's actually going on inside the text Fields if the value is still empty if we don't have a valid input and so on here we can make use of our defined off button composable let's import this the text will be set to login the background color will be set to Orange the content color will be set to right enabled comes from the button enable stage which we read here then the modifier will be set to modifier.filmx with the height will be set to 45 DP we will also apply a little shadow of 5 DB rounded Corner shape 25 DP then we will pass this loading which comes from our is loading Lambda functioner on button click is equal to on login button click like this and below this off button we will also have a text for the hint so the arrow hint and in case this Arrow hinge is null we or we simply um pass an empty string the style will be set to material theme.typography dot captioner so that it does not get too big and yeah I think this is it for our login container which can now be used in our login screen alright okay below this box where our header background and the text is into we have our login container and now we need to provide all those different state values email value is equal to login viewmodeler.loginstates dot email inputs then we have the password value which is login viewmodeler Dot Login States dot password inputs and I think we can copy this kind of a prefix the button enabled comes from login viewmodel.loginstate.is inputs valids after that we have on email changed there we can use this syntactical way pass on email input change with this two double columns then we have on passport changed login viewmodeler dot on password input change on button click or on login button click login viewmodel on login click then we have this password shown here we can again use our kind of a prefix is password shown after that we have on trailing password icon click here we invoke on login viewmodel on toggle visual transformation and can we also use the syntax with the two columns here yes I think we can okay cool and then we have Arrowhead login viewmodeler Dot Login state DOT error message input after that is loading login view model Dot Login state DOT is loading and the last thing we want to pass is the modifier this modifier has a padding of 200 DP to the top so that's it does not overlap our header background at the top then we have filmex width 0.99 F 90 of the whip Shadow will be 5 DP rounded Corner shape 25 no 15 DPM then we also have a background white gray so that it differs a little bit from our main background rounded Corner shape 15 DP then we have padding 10 DP 15 DP 10 DP and 5 DP and we will align this align toward top Center and we have a little typo here and yeah I think this is it for our login container we can already try this out and launch the application we should actually see the login container and also they had a background and yeah you can see this looks pretty cool the bubbles are still missing but we didn't Define them get so let's continue with that below our login container we can then invoke our redefined bubble animation composable and for the purple color one uh I think we need to import this first bubble color one will be white gray orange bubble color 2 will be orange and the modifier will be set to modifier dot filmex width the heights will be set to 250 DP and the alignment will be set to alignment dot bottom center and then the only thing that's left is at the bottom do you still do you already have an account and or do you not have an account click on register so this kind of stuff so modifier is equal to multiplier dot padding we will have a little padding to the bottom of 10 DP then we have also alignments alignments dot bottom center and for the horizontal arrangement we say Arrangement Dot Center then we can open the row scope we will both have a text which says no account yet style will be material theme dot typography dot body tool below this text we have an uh additional text this will have register as the text value then we will also have a modifier which we will set to modifier.padding a little start padding of 5tp I realize at the moment that we could also use this one for the padding well never mind um it will also be clickable and here we invoke on navigate to register screen then we will have a color orange front weight will be fondways.bolds and this dial will be material theme.typography dot body tool all right okay um let's try this out and also check if the input actually works let me put this in the middle and the bubbles looking cool let's also try to input an email address key apps at gmail.com empty Fields left is the hint let's also put in the password okay I think everything works here in terms of States observation and so on let's also click on register there should be a blank screen now but let's check if this also works yeah this works okay cool then we can continue with our register screen and I think I will just copy and paste everything there because there's really nothing new in the register screen and this would be almost identical to the login screen the only difference there is that we have an addition of beards and our register container for the password repeated but the rest is the completely the same so yeah I will just copy and paste this okay all right let's go just quickly over it we have the same setup here the Box inside the box with our header background and the text this time we have register as the text then we have the register container which takes all the different state values and we have for example an additional State for the or an additional function here for on password repeated change here we have the state for the password repeated value of course also on trailing password repeated I can click so almost the same only adjusted for the additional field for the password repeated text field then we have again our bubble animation here at the bottom we have this row with you will have already an account then you can click on login and here's our register container and yeah I think this is nothing new and we can also try to start this and have a look how this would work like then now we can click on register at the bottom I hope you can see it yeah should be fine when I click on register then you can see we are now in the register screen let's also type something in key apps gmail.com for example then we will enter a password I will just put in something invalid then you can see that we get a hint passwords two shorts let's also enter different numbers like this then we have passwords do not match let's have a look at them okay at the top I have one um I have only four ones and at the bottom I have five ones then I enter a new one then we have passwords needs to contain at least one uppercase jar okay um well we already tested this with with our unit tests so this should work and yeah I think this looks um pretty cool we can go back to login again and toggle a register and log in in case you want to save the entered values inside the login screen then you would need to provide additional logic but well I think this is fine so and the last thing that we want to do now is if we click on login then we want to apply some kind of logic we want to simulate a back-end requests show the circular progress indicator and if the request was successful then we want to automatically navigate to another screen okay normally Network requests or database queries are done in the data layer of our application so the data in our case is completely empty because we don't have any network requests also and also in clean architecture you often have repository classes which put together different data sources in this application here we will only use a repository class inside the data layer because we don't really have or we don't even make Network requests so we don't need API services or some kind of other interfaces and data classes we will do this in the repository class and for that we will go first to The Domain layer yeah right not the data layer because we need to define the repository interface so the interface with which our viewmodeler interacts in the domain package because our viewmodel will access only the domain layer and therefore we need to provide the interface inside the domain layer in this package and here we will create an interface called off repository and this interface will have tools to spell functions as the spell functional login email of type string passwords of type string and this will simply redo the Bool um depending on if the login was successful or not we anyway just simulate this here and then it has also a function register which also takes the email and the passwords we don't need the repeated password for the register because um well we already checked that the password match just the repeated passwords and yeah this is it for our auth repository and then we can go to the data layer and provide a concrete implementation for that we will call this of repository implement this will inherit or realize this Alpha repository interface and here we can click on Implement members Implement all and we will provide a really really simple solution for that we will delay this um for um one second and then we will simply return true of course in a real world application you would um do some some Network calls and check on the results even maybe provide the flow back or some kind of resource wrapper around the return value but yeah this is really only about the auth module and not about doing Network requests and so okay then we can go to our app module from dagger Hills we can annotate this with ad provides at Singleton because we also need to provide our off repository we need to tell deckerheads how to provide this we will say functioner provides of Repository this will return our off repository and the concrete return type will be of type of repository implements like this then we can collapse this collapse this domain go to our login view modeler go up to the Constructor and here we say privateware of repository and now tagger here takes care of providing this off repository and we defined that it should provide the auth repository Implement behind the scenes so in the data package this concrete implementation and in our viewmodel um we only know about the off repository interface here this one which is in the domain and so in terms of clean architecture the viewmodel only accesses the domain layer which is absolutely right and how it's supposed to be if we have then a look at the off repository implement we can see this Imports which also points to the domain repository of a repository so our interface is in the center in the domain layer and both the viewmodel and the repository points to it depends on it and this is achieved with the dependency inversion principle and this is a really really important principle when it comes to clean code clean architecture and so on so yeah in case you don't know about it make sure you get informed because this is really powerful now we can go back to our login view model and take care of this on login click functioner first of all we say login State it's equal to login state dot copy and we set is loading to true after that we can say viewmodelscope.launch because we need a purity routine scope to invoke this alt repository suspend functioner here we say login States is equal to try well login result is equal to all repository.login for the email we will pass login States dot email inputs and for the passwords we will pass login state DOT password inputs and after that we say login state DOT copy is successfully logged in to our login result and in case there is an exceptional of course the off repositories method here can throw an exceptional but in a real world application there can be tons of exception that happen when you do a network request or you can also provide custom exceptions I handled custom error handling in my last video which you can check up here and then you can also provide a proper error handling but here we will say for the sake of Simplicity just catch a general exception and then we say login state DOT copy error message for the login process could not log in and we will also provide a binary block for process or for State updates that always needs to be done here we say login state DOT copy is loading is equal to false and then this login state gets updated with either this one this one or this one depending on the things that happen when we invoke or repository Dot Login and then we can copy this and go to our register view model and paste it in on register click update this with register States is equal to registerstage.copy is loading to true then the register state is updated with our auth repository which we need to provide privateware off repository like this and here we call the register functioner for the email we will pass registerstate.email input and the password input as I already said we don't know the repeated password for this request because the repeated password and the passwords was actually already checked here we can update registerstate.copy is successfully registered is equal to the let's rename this register result and down here we also say error message register process and finally we will set registerstates.copy is loading to false and here we get a warning you an unused result of data class copy okay then the finally block does not um set the state here here we don't need to set register state is equal to register state to copy we also need to do this for the viewmodel here we say login state is equal to login state DOT copy okay this is it for the viewmodel and now we also need to take care of the navigation in case this login state has is successfully logged in set to true for the automatic navigation we need an additional composable component let's create this and call it net destination helper you will see why this also increases the performance it's the same principle like we had before using Lambda functions to reach the state not on the root composable here we call this snap destination helper and we will pass should navigate this will take nothing and return a Boolean and we'll also pass the destination which does not take anything and does not return anything and then we can use a launched effect and for the key we pass should navigate so we read this state inside the launched effect here in the scope of this nav destination helper then we can open the scope and it should navigate is true then we will call our destination back in our login screen we can then make use of this composable right above at the top we will say net destination Helper and body should navigate or let's first import this photoshoot navigate we pass login view model Dot Login State dot dot is successfully logged in then we again only reach the state in the scope of this composable and that's not on the login screen this will avoid unnecessary recompositions then we have a destination and the destination will be on login success navigation like this then we can copy this and go to our register screen to the top and paste it here and here we will have the register view model register States is successfully registered and for the destination we will pass on register success navigation okay fine now we can try this out launching our application here we enter an email address key apps at gmail.com we enter some random passwords and click on login then you can see the circular progress indicator and also the automatic navigation to the next screen we can also check this for the registers functionality let's click on register here we again as an email address then we will enter passwords repeats these passwords okay I see this button here still says login we need to change this button text to register of course let's click on it now we can see okay this works fine as well let's quickly change this in our register screen close the emulator and this is here for the off button no it's um where's the off button in the register container down below here we need to change this to register all right okay this was it for this off mid module in terms of clean architecture mbvm and I hope you get a slight overview how this could potentially look like feel free to use this code and modify it a little bit to your own needs of course also with the corresponding back end you could for example provide additional functionality like forgot password or stay logged in or something like this but yeah I think with the unit tests and also the clean architecture principles the clean code structure this can be a really good example for real world production App application and yeah thanks for watching if you made it this far and we will see us in the next video
Info
Channel: K Apps
Views: 6,095
Rating: undefined out of 5
Keywords: Android, Android State Management, Android Jetpack Compose, Android Compose, Android MVVM, Clean Architecture, Android Clean Architecture App, Jetpack Compose Clean Architecture, Jetpack Compose MVVM, Android Clean Architecture, Android Unit Tests, Android Testing
Id: aCjOmyd_62U
Channel Id: undefined
Length: 107min 53sec (6473 seconds)
Published: Tue Feb 14 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.