Complete Fullstack Pet Adoption Store Mobile App with .NET MAUI + Asp.Net Core Web API + SignalR

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everyone so I'm back with another video and in this video we are going to build a complete fullstack app using net Maui for our mobile application for Android and iOS and we are going to use asp.net core API with Entity framework core and SQL server and in this video we are going to implement signal r as well for our app so first let's see the demo so this is is going to be a pet adoption Store app where there are going to be pads we can go through all those pads and we can adopt some pad so this is the app I am starting it on my uh physical device so this is the first onboarding screen then we go to explore so it opens up this login and register screen we are coming for the first time and that's why it's shown that onboarding screen scen and it is showing this register mode we can switch to login mode using this so switch to login switch to register this works we can skip from here we can register and we are going to get this toast message error message that everything is required now we have this skip for now button so we can skip it and it will navigate us to the homepage where we have first this newly added pads so which are displaying here so we can move around all this data is coming from API then we have this list of popular pets then we have this you may like pets so this is a random pets list okay then we have all pad screen we tap on it it is going to open up this screen where all the pads which our application has those are going going to be list down here and and on this screen we have this pull to refresh functionality as well so we can pull to refresh it is going to make a API call and then it will refetch this list of pads so sometime it's lagging because I'm running it in debugging mode and visual studio is running night right now after that I have this favorities page so you need to be logged in to load your favorite pads because I'm not logged in so we cannot see anything on this page then we will go on profile page where it is showing this user is not logged in so for my adoptions it will say same you need to be logged in then we have changed password and for this also we need to be logged in okay now let me go to the homepage if we tap on any of the pad it is going to open up the detail page for that particular pad and this data is coming from API that's why we have that activity indicator that loader so now this is the list the detail view where we can can see image price description breed gender age and everything this pet is already adopted so that's why we cannot uh adopt this this button is disabled adopted we can add this pad to fabes but as we are not logged in so it will not allow us now let's go back check some other pad which is not adopted maybe this Max so this first it checks the status then yes now we can adopt this pad because this pad is not outut so we can directly adopt it now if I adopt it it is saying not logged in you need to be logged in to adopt a b do you want to go to login page yes or no so using no nothing will happen and if we press yes then it will redirect us to the login page and here we can simply login so I have one user setup test we can register a new new user as well but right now let's use this only so I have this 1 2 3 4 5 6 7 this is the password and I have logged in now and we can see hi test user test user is the name of this user now if you go to profile page here also we can see test user and initials in this rounded Avatar view now if you go to favorities this page is going to be loaded we have these two pets added to favorities on Prof file my adoptions we can see the pets which this user has adopted okay then let's go to homepage again and we were trying to adopt some pet we are trying to adopt Max so let's see now first thing we can add this pad to fabes now it is added now if we go this is Max if you go back and go to favorties now we should see Max which is at the first place right and if you remove this Max from fa it is here it got removed if you go to homepage and open Max again now this heart icon on the right Top This is not going to be selected because we have removed that cool now if we adopt it and we have adopted this pad now if you go to explore more pads now if you open Max it should show adopted right and if you go to profile and in profile if we go to okay my adoptions only so here we should see this Max at the very end we can see Max we can tap on it and we can see the complete details of this pad here again so this is the app on physical device now let me show you the app on iPhone IOS so on Android emulator this is going to be look and Fe feels same right now let me stop it on my physical device let me start this app on iPhone simulator so I selected it let's run it okay so it is opening on iPhone okay so this is onboarding screen this is not going to be shown again this is going to be shown only when the user is coming to RF for the first time let's explore we are on login register page we can same switch to login register let's log in with the same credentials test at test.com 1 2 3 4 5 6 if I enter incorrect password then we are going to get this error alert error incorrect password so let's fix the password 1 2 3 4 5 6 7 login now we are on homepage and here we can see all the newly added pads we have this popular pad section we have you may like this pad section we can tap on any pad it is going to open up detail page this is fine we can add this pad to fabes go back this pad is adopted right now let's go to all pads and here it is going to load all the pads we can see all the pads and we can tap on any of the pad it will open up details this P we already added this to our fabric so that's why this uh heart icon is in this redish color go back go to favorties we have our favorite pets we can remove from here same thing if you go to profile we have this test user initials my adoptions my adoptions we can see our adopted pad go back and change password we can change our password from here okay then we have this log out button from where we can log out easily cool now let's just stop it and let's try to run it on our uh this emulator I want to now we'll see what is the use of signal R in this app okay so for that I need to AR run the app I will run app on all these three devices so first let me set it up on Android emulator all right so this is on Android emulator and it is going to behave same switch to login this I'm uh skipping for now then same thing we can see all the details okay now for Signal R what is the use of signal R in our app for that what I'm going to do first let me open my physical device and then I'm going to open it on iPhone simulator and this is already opened on uh Android emulator so in this Android emulator I am not logged this says hi stranger welcome we are not logged in in my physical device I am logged in as high test user and in iPhone I'm going to register a new user let's see how this works so I'll go to profile log out then I'll go to profile again login and this time I will register let's register a new user let me say AB Prince my name was some test email test test.com and then password 1 2 3 456 register this email already exists so let's say test at the tast one.com register and we are on this page and AE Prince that means that b was missing but we are good so ah hey Prince it sounds weird but now this user is also logged in now the point of signal are here is these are all uh real pets this is a pet adoption store so let's say I have opened this Rani pet from here this is already adopted let's find some pet which is not adopted so Daisy this is not adopted now let's say I was looking at this pet and there is this uh this test user is also looking at the same pet let's find where daisies daisy daisy daisy oh let's try in all pads screen daisy daisy daisy where are you here is so now if the test user also opened this pad and you already saw that message right so the point here is if some user was already looking at this pad and I just uh show interest in adopting this pad so first thing I'll do I'll open this uh this pet I'll try to check the details but at that time if some someone else adopts this pad I was still making up my mind that I am going to adopt this I'm going to checking all the details but at that time someone some other user has already adopted the pad so we should somehow notify the user so whenever I am opening this pet so all other users who have this pad opened on their screen it should say that someone else is also viewing this pad so if you want to adopt it you should hurry you you should just adopt it quickly the reason is these are not some inventory items that we have this product which have we have two or three quantities but that is not the case these are real pets that means there is going to be only one pet with all this description this name breed gender age everything this is going to be single pad so only one adoption can be there for one pad so we need to notify users about this so you saw that right let me show you this this same thing so Daisy I will open this Daisy again from somewhere from this Android emulator this is not here let me go to all pads so at this screen I am uh at this all pad screen I not logged in in the this third screen let it open h so let's do this I can try from here also if I open this Daisy pet again then keep an eye on this left physical device it is going to display that uh the toast message that someone else is also viewing this pet so you see someone else is also viewing this pet so you should better hurry if you are planning to adopt this pad okay now let's open this same pad on this emulator I don't this is my controls are not working properly okay so from here when I'll open this where is it Daisy [Music] Max Dy it here it is here so if I open it on my emulator we are going to notified on my physical device and iOS simulator at both of these screens just uh on top of this adopt now we will see uh notification that someone else is also viewing this Pat so you see someone else is also viewing this Pat that means we need to H if and on this screen as well we saw that someone else else is also viewing this pet so if we are opening the pet we would know that okay someone else is already looking at this pet so if we want to adopt it we should hurry so on this emulator I'm not logged in so there is no point of adop now and on my iOS and physical device I am already logged in so I can adopt on these so I'm going to adopt it on the this uh iOS simulator so as the moment when I adopt it after adopting we are going to not notify all other users so right now my physical device and Android emulator for both of these screen I'm going to have that notification that someone adopted this pet so you won't be able to adopt this pet now and all these buttons are going to be disabled so let's try it now I'm saying adopt now and you see someone already someone has adopted this Pat now and now all these buttons became uh this is disabled now explore more pads now if I open it again on my screen now here also I'm going to say adopted this is already adopted right now go to profile my adoptions here I have only this one p adoption so this is here so that is the complete app which we are going to build in this video from scratch to end we'll do everything we'll uh create models we'll add data we'll set up our Entity framework over database We'll add migrations we'll create our API controllers complete business logic then we'll work on UI design for our mobile app then we are going to connect our mobile app to our API and then we are going to have that authentication login and register we are going to use JWT tokens in this and after setting all these things we are going to use mvvm and we are going to use preferences Shar preferences to uh keep track of the currently logged in user and if we have shown that onboarding screen or not so if I close this app and open it again I'm going to get the same user because I'm already logged in so we are storing this device this uh information on device we are storing JWT token which we are passing to each and every request to the API and then at the very end we will Implement signal R and then we will have this uh design fix for all for both the platforms Android and iPhone so you know we there are some design considerations so we can the same design we need to do some additional stuff to make it work on both the platforms so we are going to do that as well so all that we'll do from scratch to end okay so without was wasting any time let's get started all right so I have created this project this solution which is this Pat adoption which has these three projects Pat adoption ma. API mobile and do shared and as the name suggest this mobile is for our mobile application Mai app then this API this is an asp.net core web API project and then the shared this is a simple class Library project and all the classes models dtos enums which are going to be shared between these two projects we will have those inside the shared project okay so in Mobile Mai application what I have done in the resources in images folder I have added couple of icons and two images which we are going to use in our app apart from this I have copied this U font we are not going to use this default open sense regular font we are going to use this open2 font and after this and resources Styles colors I have modified this primary color this is now this one it was some that blue or purplish color which GI by default I modified this to the color R color theme basically and then I have added these two color nodes so BG color and T bar color that's all I have done in Maui and mobile project then in API project what I have done I have installed this new get package for jwtb authentication so Microsoft as net core authentication jwtb after this uh in app setting. development Json I have this connection string so you can modify it as per your requirement or your system configuration I'm using my system and then I have added this JWT key with these three values isue expiring minutes and key to be used in our app to generate JWT token and after this what I have done um in Services I have created services folder in that I have created token service. CS file and inside this file I have all the configuration all the code related to JWT brr token generation validation all that thing I have in here and all these things we are getting from our app settings only which I just showed you JT expiring minutes isser and all these cool and apart from this I have created this data folder and in that this entities folder and these are the entities database entities which we are going to use in our app okay so first we have pet or maybe before that let's see we have user so this user. CS it has simple ID which has this identity name email and then plain password I'm using but this is not good for production purpose I'm just using this plain password for the sake of Simplicity in uh real world in production level apps you might want to implement authentication using some third party provider or maybe using Identity or any other provider and if you're not using any other provider you might want to implement custom authentication so for that uh hashing is a good way so for that you can use this hashing hash and salt if you want me to create a dedicated video for this for custom authentication using salt and hash do let me know in the comment I can plan a dedicated video for this cool but in this we are going to use this plan password after that we have this pet entity so it has this ID which is unique ID then pet name pet image then pet breed gender and this gender after that we have price date of birth short description number of views so this pad how many times this pad has been viewed by uh users then adoption status and is active these all fields we are using in here and if you see we have we are using two enms here enumerations is gender and adoption status so these things we are going to to use in mobile application as well so for that I have added this these two in our shared project so shared we have a folder enumerations in here we have one gender enum which is male and female and then we have adoption status which is available and adopted so if the Pat has not been adopted yet it status is going to be available and when the P Pat is adopted the status adoption stat is going to be adopted okay and after that we have this user fabries so user can Mark pads as fabries so for that I have this mapping table this is many to many so we have user ID and pet ID so we are going to keep those mappings inside this table after that we have user adoptions so whatever pet user has adopted all those are going to be here okay and this is going to be uh one to many from user to pet because one pet can be adopted by single user only but one user can adopt multiple pads so in here I have ID user ID Pat ID and adopted on when this Pat was adopted this current user ID and the pat ID all these so I have all these entities here cool and now if you go to Shar we have this dtos folder in this folder I have added couple of sorry couple of classes so all these are dto data transfer objects all these we are going to get response from the API to our mobile application or we are going to request test uh these models from mobile application to our API so first I have API response I have two flavors of this one simple API response which has its success and message so using this one if we don't want to return any data we just want to return the API response we are going to use this one so here it will indicate that if the response was successful operation was successful or not and if we have some message in most most of the cases we'll have error message then I have these two Factory methods inside this API response so these are kind of shorthand methods we can directly say API response. success it will return us this is Success true and message null and then same for fail and then I have another flavor of this API response with this generic type T data so if we want to return some data from the API along with status and error message or other message we can use this one so inside this also we have it success string message and we have this T data data as well so whatever data we are rning we can access from here and In Here Also I have these two same uh Factory methods short hand so we can use success and fail directly after that we have login request DTU so when user is going to login we'll pass this email and password okay then we have register request d i uh showing this the way in the for in which order we are going to use kind of okay we have register request DTU so it is derived from login request DTU so in login request DTU we had email and password so in register request dto we have email password and this name so user's name name and then email and then password these three things and from login and register from both of these sites we are going to get this Au response DTU in which we are going to have user ID which we'll use for so many purposes then we have name users name and this name we are going to display it on the UI that with the greetings that you are the logged in user and then we have this token the JWT token we are going to get it from the API after that I have this Pat list DTU and Pat details DTU so in Pat list DTU so we are going to list these on homepage newly added pads popular pads and on all pads favorties pads so we are going to use this couple of times so in pet list dto we have pet ID pet name pet image pet price and then pets breed all these things then we have P details D which we have are going to use on the detail page with complete details and this is derived from pet list dto so it will have these things as well as these properties from Pat list D so ID name image price breed we have from Pat list dto and then from pet details Ed uh dto we are adding is favorite if this Pat is users favorite if user have added this Pat as favorite is then we have description gender date of birth adoption status then I have these three computed properties so first I have gender display I want to display the gender that is this Pat male or female so for this I'm using this gender do2 string so from this enum then we have gender image so for gender if the gender is male I have different icon if the gender is female I have different icon so for that what I'm doing in gender image I I have simply applied a switch statement here on the gender property if gender is male we are going to use this male icon which I have in our mobile application images we have this female. SVG and male. SVG by the way all these icons I have downloaded these icons from uh box icon.com and the pet images I got these from pexels and pixabay so in our API project inle root images pads I have this photoc credits. txt so you can check from where I got which image all these images most of these images are from pexels.com and there are I think one or two images from pixabay okay after that so I have gender image then then we are going to display age of the pat so for this I have this computed property here in getter I simply checking getting the difference from current date time to the date of birth and this is not 100% full proof uh it is not incorporating all those leers and all other things so this is for simple purpose this is a very minimal uh age calculation so here what I have from this difference we I'm getting this days and on this days I have applied a switch statement so if the days are less than 30 I'm going to use that let's say 20 days 30 days it will display the age like this then if the age is between 30 and 31 including 30 and 31 so I'm going to display one month and then if the age is less than 365 days then I'm going to display the months so 5 months 4 months 2 months 1 month something like this and if that's not the case it does not fall in these three categories that means it is going to be greater than 365 days that means in years so then I'm going to display these years and right now I thought maybe we can add one more condition if we want we can say if this is 365 then we can simply say one year like this one here and if that's not the case if it is greater than 365 then we'll say 2 year 3 year 4 year or whatever so this is the simple calculation great cool so I think that's all the setup I had now we'll start working on the things so first let's add the Entity framework to our API we are going to use Entity framework with SQL Server so close all tabs cool so in API project let me open new get packages from here we are going to install two new get packages first is going to be Entity framework core I'm searching it I'm not going to install it directly from Entity framework code I'm going to first install Microsoft Entity framework code. SQL Server so it is automatically going to install the required packages which are Entity framework and all other dependencies basically cool apply accept and apart from this we are going to use code first so we will use migrations so for that we are going to use Entity framework code. tools so this package this provides all these migration commands add migration bundle migration drop database get database get migration all these commands we are going to use the migration in this to save everything cool we have installed Entity framework core uh packages now let's start working in this data folder so this data is related to all the database related stuff so we already have this entities folder where we have all our entities inside this data I'm going to create a new class which we'll say let's say p Contex so this is our database content this should be an derived class of DB Conta T which will come from Microsoft core sorry microsoft. Entity framework core and let's add the Constructor this DB context options Constructor with this generic parameter of type this tool and after that let's have let's override couple of methods first we'll override on configuring and this one we are over riding for local debug purposes what I like I like to see what queries it is using so for that we can say options builder. log 2 and inside this we can use console. right line like this so what it is going to do whatever queries it is generating EF core is generating and running on the database side it is going to log this it simply calls this method so we have provided this delegate so it is going to write in console whatever queries it is uh running against the database okay now this should always be in debug the reason is it is going to fill up the console and it is an additional stuff we don't want this in production because there is is no sense of it so this should execute only in the debug mode that means when we are developing our app cool okay so apart from this let's add our entities first so we are going to add our entities DB set what all entities we have we have pet user user adoption and then user favorities so let's add all these so we'll say DB Set pet p pet this one pets and then we'll have DB set user users and then we'll have other ones as well so DB set user favorties user favorities and then the last one DB set user adoptions user adoptions like this cool okay now this user Fab is for user adoptions we have this unique ID right but user fabri we don't have any idid so we are going to use a complex ID composite key basically this user ID and Pat ID both should be part of primary key so if we want to do it sorry using data annotation we can add column then order but for this one the fluent approach makes more sense in order to add that additional configuration we need to override one more method which is on model creating inside our DV context in here we are going to add that configuration so from model builder which is a parameter of this on model creating we can have this entity and the type we are going to add the configuration is for user fabes now we have access to this type entity and here we'll say has key so this has a key and that key is going to be user favorties UF we'll say an anonymous object where we'll say UF dot user ID comma UF dot Pat ID okay cool and I think we are good but before that okay let's do one more thing so if you are familiar with ef core or Entity framework in general it automatically tracks all the changes what we are doing inside this DB context and then that CH using that change tracker we can save changes in single go into to the database but in our case most of the calls are going to be read only what I mean is the change tracking how it works first we'll fet some data and Entity framework will start uh uh tracking the changes for that set of data if we have some collection it will start tracking for that particular collection and then if you modify something in that then we call Save changes then it will simply know that these changes are there using it inbuild change tracker then it will save all those changes to the database but in our case most of the calls are going to read only so we don't want implicit change tracking we will use that explicit whenever we need it right so change tracking is good in general but it comes with its performance overhead right because it is going to track each and everything which we don't want we don't need actually so for this what we will do on this options Builder we are going to set the query tracking Behavior if we have used query tracking Behavior this is a method and here we can have this track all no track no tracking with identity resolution so just no tracking we don't want any tracking automatic tracking right so now whenever we are going to say uh maybe context. Pats do to list ising to arring so it will simply have without any thing if we have not added this thing then if we say context. Pats do2 list. two array in that case it is going to Fest all this list all the pats then with it will start tracking all those changes which we don't want right so we can have this so it is a performance boost in our application great so I think that's pretty much it for pet context apart from this we will just have one more thing which I'm going to add later uh that seeding data but before that let's we have added spat context now let's register it in our main program.cs so that we can start using it cool so inside this one uh the order does not matter it should be just before builder. build and after word builder web application create Builder so inside this it can be anywhere okay and start adding here so we can say Builder Dot services. add DB context and the type of context is going to be our pad context cool inside this we need to provide our options so these context options here we'll say options. use SQL Server because we are using SQL server and inside the SQL Server we have this overload which is we need to provide connection string and if you remember we already added a connection string in app settings. development which is named as pet we can get this connection string from this connection string so here we'll say word connection string equals so Builder do configuration from this configuration we'll say get connection string and here we need to provide the name which which is this name so this is pet just copy this and add it here like this cool now we can directly use it here so we'll say connection string and after this connection string do we need to set anything else okay fine save and after that this DB context by default it registers this as scoped and again scoped is uh good if we need the same instance throughout the request life cycle but in our case we are not going to use it so we we can simply free up our memory using service lifetime. transient so just create a new instance whenever we need it and then just dispose it as soon as you can cool so database context services. add DV contact so this is fine after this we will start we will add our seeding data basically so for that let me take a quick break H so I have copied the seed data so this is the seed data I have 35 pads with all this data the ID name breed price description gender and all other things so so I have created this private static initial patch data method and now we need to seed this data so for that in our pad context on model creating what we'll do we'll say model builder. entity Pat now we have access to this entity Pat entity and here we have a method has data and this has data we can provide our list of data which we want to uh SE basically the initial data for this entity okay so here we'll say initial patch data like this and now we are good everything looks fine great so from API side uh the identity framework code database setup is done now next thing is let's create the uh migrations okay so migrations are basically the code which runs all the model EF core entities related changes converts the scripts writes the scripts and those scripts those migrations can be run on the database to apply the changes to the database so for this let's open Package manager console and here we need to select our API project let's set API projected startup project API project from here as well default project and now we'll say add migration and now name of the migration so right now let's say initial now there is one thing by default it is going to create a migrations folder on the root of our API project but all the database related stuff we want all that data inside this data folder so we will explicitly provide one setting one configuration which will hyphen o that means output path where we want the migrations to be so here we'll say data slash migrations so now it is going to add this migration inside the data folder and then migrations folder so let me press enter and if everything was fine it will generate migrations all right so it generated this this operation was successful and if we check now in our data folder we have this migrations folder where we have this files and if you quickly check it has created this up method so create table pads with all these configuration ID name and all these after the users user adoptions user fabes and then insert data in pads it is inserting all this data then creating some indexes and we are good now now we can run the all these migrations on our database so for that what we can do on this package manager console only we can write one more command which will be update database so we can use this one so it will run the pending migration right now there is only one pending migration which is this one but I'm not going to use this I'm going to show you a different way not not a different way we'll migrate the database programmatically and so that whatever changes we have if you are going to run this solution you don't need to run this update data database command explicitly so for that what we can do we can simply go to our program. CS file and here what we are going to do let's create a method here so we'll say static void let's say apply DB migrations and we'll get I service provider as a parameter service provider and inside this we will create a scope so we'll say using word scope equals service provider dot create scope now we will get a database context so we'll say DB context equals and this we can get from scope do service provider dog that required service and this we need from pet context now we have access to this DB context so let's name it context only or maybe DV context fine so we have access to this now on this it provides some helper methods we can say DV context dot database dot now we have one method which says get pending migrations okay there is async version as well I'm not using async version so if get pending migrations this returns and collection so we can check if we have any pending migration right now we have this one pending migration because we did not run anything if that's the case we will say DB context database do migrate so now this code this piece of code is going to run the pending migrations automatically on the database now we need to just call this method and the point from where we need to call this it should be after builder. build when we have this app after this we could add it anywhere but I'm adding it inside this app. environment. development because we want this inside development mode only so that's a safe place to run pending migrations so we should not automatic uh we should not run automatic pending migrations in the production environment because that could break some things break some data and we could have data loss so for this apply DV migrations and we need service provider that we can get from app doservices like this and boom now whenever we'll run our a uh this API so let me show you I'm adding a breakpoint here API is already selected right so let's run the API and let this breako hit whenever we our API is going to start for the first time then this method is going to be called now if we go here we have scope we have access to this and this time it came inside this if condition because we have pending migration that is that one pending migration now if we run it we pass through and the migration was successful how can we know this I can show you database but let's try this I'm running the API again this time it should not go inside this if because right now we don't have any pending migration so from if it will simply come out and we are good that means there are no pending migrations and everything worked fine great so now let let me show you if this will actually run for other changes so maybe let's go to some entity let's go to Pat entity and let's add something let's make this breed required required okay so I modified something in this entity so we need to generate a new migration for this so here what we'll say let add migration we'll say make breed required this name is up to you you can name it whatever you want cool now if we check it created one migration and this migration is Alter column column name is breed on the table pad and now it should have required nullable fals initially n Lael was true now n Lael is false so this field is required now if we run our API it should again go to that if condition because now we have one pending migration so this change we did not run it on the database yet so if you continue continue and now it should go to yeah this if condition so it came here that means there is there are some pending migrations in our case there is one pending migration now it is running it I pass continue and we are good let me try to run it again this time it is not going to go inside this if condition because now we don't have any pending migration again after if it came out directly cool so I guess most of the stuff is done the setup part is done on the API side now let's start working on our services for API so after creating Services then we'll create our controllers inner Services folder let's create a new class and this is going to be all service for uh login and register okay let's have a Constructor and we need to inject our pad context let's call it context and in this we will need token Service as well we need to generate the GWT from here so let's create private readon fields for these tool now first we will have have our login method so we'll say public async task and if you remember we had that Au response D in our shared dto so we will return this from here we'll say login async and the parameter will be login request D let's call it D okay great now first thing we will patch user using the email ID so we'll say DB users of wa context dot users dot first. default async and U goes to u. email equals equals d. email like this okay so now we'll check if this DB user is not null that means we have the user or let's do the opposite if DB user is null we will directly return return so it should be auth response dto no no no it should be API response of auor response D like this we are going to return return API response from all the uh Services we going to use this class cool so if DB user is null that means this email does not exist in our system so we can call this Factory method fail and then add a message and here message will say user does not exist and we are going to return this cool if that's not the case then we'll check for password so we'll say DB user. password password if this is not equals to d. password the password which user just provided if this is not equal then we'll say incorrect password incorrect password okay now if we reached at this point that means everything is fine user exists in our system and uh the passwords are matching so that means we can go ahead and generate a token so here we'll say what token equals we have our token service and on this token service we have generated JWT method and in this method either we can pass claims or we have a helper method other overloaded method there we can pass the user object directly so we'll say DB user like this and then additional claims we don't want want to add any additional claim so we are good with this if you go to this generate JWT here we are adding these name identifier and name these two things in the JWT token so name identify is actually user ID and name is username whatever name he has provided cool now we have this token now we can return API response or response DTU do success and now we can pass our data so data is going to be author response D's object user ID which we can get from DB user. ID then usern name which we can get from DB user.name and then token which we have right before this call so token now our login async method is ready to be used great let's collapse this and and let's start working on next method which is going to be a register async method so here we'll say public Asing task and the return type is going to be same like this mm and here we'll say register async and this time we'll have register request DTU like this cool so here we will check if this email ID already exist in our system so we'll say existing user and here we'll say a context. users do first. default async U goes to u. email equals d. email okay now we check if exist ing user is not null that means this email already exists in our system so from here we don't want to continue because we cannot we should not register a new user for the same credential so from here we will return failure so we'll say email already exist now if the code flow passes this condition that means everything is fine now we can register this us insert this user in our database so let's create a variable here and create an instance of user entity okay so for this what we'll do we'll add all the properties email name and password because we're using plain password password if we have used uh some hashing or some other technique then we might want to create salt and hash before then assign those here okay so now we have this DB user object after this what we'll do we'll say await context. users do add async and we'll add this DB user here cool and after this we will save changes so we'll say a context do save changes asnc like this cool now we have this user in the database now next thing is to generate token and return the respon so we can simply copy these two lines from login async and just add these here so we have generated our token and we are returning the response great so looks like our Au service is done cool now let's extract an interface so extract interface for all the both of these methods okay and we have iot service let's move this to same pile cut because these are smaller two three methods so we can add these here only but it's uh preference how you prefer these you could have these in single file separate file as well there's no issue with this we have this off service after this off service let's create a new service and this time we will create our pet service so we say Pet Service okay so inside also first thing let's add a Constructor let's inject our pad context context let's create a field and now let's start working on the methods so first we will use public async task API response which is the returning type pet list D array of pet list D and here we'll say get newly added pets and we are going to have a count here how many newly added pets we want that we'll have here here let's do this here we'll say word pads equals here we'll say await context do pads dot now we'll say order by descent sending when we say newly added so we can use p. ID in our case because the ID is auto incremented so the greater the ID the recent the pet was added in our system right so that's mean order by descending means the highest ID is going to come first that means the Recently Added pet is going to come first in this list cool and on this we are going to have take count and then two array isnc like this cool and then we can simply return API response of pad list D array what is the show okay dot success and then this pads now we have issue it returns this call returns pet entity but we want to convert that pet entity to pet list D so we need some mapper I'm not going to use any third party mapper for this because we have uh the only two places only two classes we need we need to convert pet to pet list D and then we need to convert pet to pet details D so we are going to get only two MERS so for this what I'm going to do let's create a folder uh maybe let's call extensions okay I don't know if this name makes sense or no but we are going to have our selectors in this these are mappers actually but I'm calling it selector because it we are going to use this for selection so here I'm going to say public static class selectors and first thing we'll say public and the type is public static pad list D okay and here we'll say pad to P listed you something like this okay let's have it as a property and this property is going to be of No it should return some expression not this because we are going to use it directly inside here the selection for projection right so we'll use expression of funk of the incoming type in input type will be pet entity and the output type is going to be Pat list dto like this now we can say p to Pat list D there should one more great and here we could say p which is pet and from this pet we can select our Pat list D like this and now we can map all the properties cool so we have ID image name price and breed so everything is fine cool let's use this selector in here so maybe order by descending or before order by descending we are good or maybe after take so here we'll say dot select and this time we'll say selectors selectors which are which should come from api. extensions dot P to pad list now we are good okay get newly added pads now let me copy this thing and let's create other uh methods which we need for example first let's fix it with a sync copy it again paste it here this time we would say get popular pads ASN popular pads Asing so what I mean by popular is the pads which has view count the more the view count the more popular the p is right and view count gets increased whenever we see details of that pads in our mobile app in our Maui app great so selector is fine this is fine but here we will the order by descending it would be view so it should be before uh this select should go after take so here we will say context. patch. order by descending p goes to P do views that means order by views take whatever number of uh pads we are expecting then select then two erasing and we are good great after popular pads let's have one more method for fetching the random pads that is also we are going to use in our app so Random pads this time this order by ascending descending does not matter and we'll say guid do new guid order by this guid GD so it is going to be random cool okay so we have all this now if you remember the demo I showed you we had one screen where we were displaying all the pads so let's have one more m method where we'll say get all pets get all pets Asing this time we don't want discount we can remove this count and we can remove this count and Order buy is up to us if we want we can if we do not want then we can skip this order bu but I'm having it so it will display in the descending order cool now we have got all pads as well after this we need one more method here and that is going to be the pat details so for this we'll say public async task API response pad details dto here we'll say get pad details as sync like this and here we have a pat ID as a parameter okay so first thing we will fet the pad so let's say pad details equals we will say a context do pads dot first. default first or default p goes to p. ID equals equals Pat ID and let's use first or default ISN now inside this whenever we are viewing any pad I mentioned that we have that view count so we need to increase the view count for this pad so for that we will add one method here in this chain which will see as tracking because we want chain tracking enabled for this call okay okay after this we'll say pet details is not null which we know it not going to null but let's have for safer side here we'll say pad details do views Plus+ we want to increase the view count okay and when we increase the view count let's save the changes save changes asnc so this is going to increase or maybe not missing we can have save changes this time so that it can just wait okay now we have saved the changes so view count is increased after this now we need to modify uh not modify we need to return pad details dto and this pad details is of type entities pad so we need to map this pad to pad details D okay so in our extensions let's create a new class and this we can say mappers and it will be public static class mappers and here we'll have an extension method public static which will return P details D you so we'll say map to pad details D and we will add this extension method on the pet entity P pet like this okay and from here we will simply return new oh my God new pet details d let's use P here okay so we'll have to write less now let's start adding all the properties dat of birth description gender ID image P do image then [Music] name and price is favorite we don't have this on right so we can skip this and age gender display and gender image these are computed properties so we don't want to map these we can say like this cool save everything and we are good now now let's go go here and from here now we'll say word pet D equals we'll say pad details dot map to pad details D now we have this pad D object here right we can skip this warning because we know this is not going to null and from here we can simply return API response of Pat details dto success Pat dto great looks like everything is fine now cool save everything let's extract interface for this add to current file okay we have all these methods now great now let's go to the next service which is going to be user pad service right so inside this we are going to use all the API calls or all the operations which are which requires logged in user right so let's create a new class and this we'll call user pad service right so Constructor let's inject our pad context context like this cool now inside this first what we need first we have an operation we can toggle the favorite pet right we can Mark pet as favorite and we can remove uh pad from fating so let's do that first so first public tasing task and from this call we don't want to return any data so the return type is going to be public using task API response directly without generic parameter and here let's say toggle favorities a sync like all right here we'll say in user ID and int pet ID cool so here first thing we will patch the current status so we say why user favorite and here we'll say await context. user favorities and from here we will fetch first of default async UF so here we'll say uf. user ID equals this user ID and pet ID equals this pet ID great after this we will check if user favorite is not null this means this pet was added to user's favorite and now we need to remove it from there because user uh tabed on that heart button to uncheck check that okay so for this what we can do we can say context. user favorite. remove user favorite like this if that's not the case in else we need to add this that means this does not exist so we want to add it to the fabes so for this we need to create an instance of that user favorite so let's use this variable only here we'll say new user favorite let's add this name space r and here we will say user ID equals this user ID user ID oh my God user ID then pet ID equals this pet ID cool now we can directly add this user favorite so we'll say a context do user favorities do add async like this and after if and else in both the cases we are going to say a wait context. save changes is sync that means apply this changes to the database and then we'll simply return API response API response. sucess cool okay we have added this toggle favorite method now when we added the toggle fav then there is one screen where we want to fetch all the favorite pads for this user for for that we can copy from pet a service basically so let's use any [Music] method add it here the name it to get user favorities async for the user ID so here we'll say context dot user favorities now we need uh details of the user or no we don't need it do we need let's see so user fabri is where UF uf. user ID equals this user ID from this we just need to select pet we need pet details cool after this we can use this select so now we are going to convert Pat to Pat list DTU and then we can apply two array Sy cool pads and now we are returning this pads we are good cool what other method we can have in this we'll have H when user adopts a pet we will have that method and then we'll have one list of user adoptions so first let's copy this method first we'll have user adoptions list so here we'll say get like this get user adoptions I think like this okay and this time instead of user favorities we will use user adoptions and all other things I guess can be same no need to change anything okay after this we'll have one more method and that is going to be the main method public asnc task API response this is adopt pad ising this is when user presses that adopt uh adopt Now button so we'll have user ID okay now first thing let's access the pet so we'll say p a wait context okay not just user ID we need pet ID as well P ID so here we'll say context. pets dot first. default async we'll say p goes to p. ID equals pet ID and we need to modify this so we'll use as tracking like this cool now we'll check if pet is null although this is not going to be the case but let's have it so if p is null we will say return API response do fail and we'll say plus say invalid request after that we'll check what is the adoption status of this P maybe this pet is already adopted for this we'll check if adoption status let's add this using so we'll say adoption status dot um if this is already adopted so we'll return again this fail request and we'll say pet is already adopted or maybe let's make it Dynamic so here we'll say the name of the pet which is pet. name is already adopted okay cool now if that's also not the case what we'll say we'll say pet Do adoption status now we are modifying its adoption status so this Pat is the entity which we just got from database and we are modify it adoption status to adopted after this we'll create a user adoption object new user because we need to add this in user adoptions table there we'll say user ID equals user ID and pet ID equals pet ID like this and then we'll add this user adoption a context. user adoptions do add async user adoption and then we'll save all the changes so we'll say a context do save changes async cool and after this everything is fine so we'll say API response do success and we'll return it great now everything is going to work fine but let's wrap all of this in a try catch block try in catch we have this exception let's not throw it and from here we'll say return AP response do fail and here we'll say error adopting or error while adopting something like this and here we can display the error message like this cool now there is one crucial Point here so when I was demoing it so in this case these are not uh multiple quantity products these are real pads and there is only one pet for single description so if I want to adopt some pet that is going to be only single pad so let's say I was looking at the pet in our mobile app someone else also looking at the pet at the the same time and I pressed adopt now and the second user also pressed the adopt now so both of request came here somehow if there is any raise condition so we both might come to this status so not so how it is going to work first request came to this pet it generated this query and went to run the query then second request came to this it was great first request came back then second request went here then first request goes here and adoption status was not adopted so it came here and when the SEC first request came to this line number 85 await hit and it the control flow goes back to the pet to the second request then second request came to this section so this was not adopted the second request also passes through now we have both of these requests both of these us users are adopting the same pack that is not what we want so we have two approaches either we can change this method to be sync so we can remove a sync and all the await calls or if we are using a sync and AIT we can use Sima for Slims to make this this section synchronous okay so let's use synchronous uh sorry not synchronous let's use Sor SL so okay inside this on the very top I'm going to have a private static read only s for slim let's call it s for and slim and here if we check in its Constructor we have initial count and Max count so initial count is one that means one thread is going to execute inside this then is maximum count how many concurrent uh request are allowed inside this section so we want only one we don't want to allow concurrent request to use the S for slim and pass through this okay so we have this we can remove this thing new is automatically going to use this now in the SE for slim when we going inside try we will say s for slim dot here we have a method which is weight async and it should be a waited now when we say a wait seor do weight ising first request will go through and all other request whatever request is coming to this thing it will simply wait this SEMA 4 to be released okay and when we are going to release it we are going to release it at the very end so we can again we are going to release it here and insert catch as well so if there is something which needs to be done inside both try and catch we should move it to finally in finally we'll say SE for do release cool so now this is kind of single turn so only single request is going to insert uh pass through this region at a time now let's see the same same thing I taed on adapt now you taed on adapt now we came here if first request was mine my request came to this one my request is going to pass through this and your request is going to wait for the SEMA from for to be released so your request is stuck at 970 but my request which was came first so it went ahead it fed the pad checked adoption status is not adopted it added the change the adoption status to adopted create created this new object added it to the database saved changes return and when this return hit it will go to finally and on finally the sea 4 is going to be released and as soon as this got released the second request which was your request it came to this and now it can pass through this request now you also F the same your request F the same pet it came here pet is not n yes but this time Pet's adoption status is adopted so your request is going to return from here so we will there will only be one adoption for a B for sure using this thing great so let's extract interface for this as well so let me extract it to the current file and we are good cool so I think all the service layer related code is done in the API side now we need to register these services so let's go to program.cs and here we are going to register our services all these services are going to be uh transient only so here we'll say Builder do services do add transient and let's start first o pad token user let's add all this Au service then second one add transient token service then add transient pad service and then the last one transient user pad service cool great now we can go to the controllers so we had this weather forecast controller we don't need this controller now right so let's remove this controller to delete this and it has this weather forast model as well so we don't need this as well remove this cool now in our controllers we are going to add our controllers and we'll have three controllers first let have a controller this is going to be API controller add and this is will be first Au controller okay now let's add one more or maybe let's me copy this paste it so after all controller we are going to have our pads controller and then we are going to have a third one which could be users controller user pads controller but we'll say user controller okay now Au controller it will be anonymous allow anonymous we don't need authentication to this because this is the login request login and register request we don't have authentication at that point then we have pads controller inside this we are going to fetch all pads p pad details and all those here also we don't need authentication but for users's controller for this controller we want authentication because this user needs to be logged in then only we can f the users details user fabes user ad options and all those things on this I'm going to add authorized attribute because we want this to be authorized the user to be authorized for this okay so let's first start working on o controller inside this let's add Constructor and this is going to be we are going to inject our o service o service H service like this and here we are going to have two methods public as sync task API response of all response dto this is going to be for login and for login we have login request D like this from here we could say await Au service do login Asing and we can pass this DT we are good and the we need to decorate it with HTTP post this is going to be a post method and on post method let's add the route as well so login so the complete route will be this API SL controller which is O So API sl/ login so it will be API SL slash login like this [Music] log cool same thing we'll do for register so let's copy this paste this and here we'll say register register this should be register request due to you register request DTU and this should be register I think and this should be not o service it should be I service okay register the URL going to be or register like this cool so our Au controller is ready after this we we have our patch controller and for patch controller we will have all those methods which we have defined in our Pat service so first let's inject the pad service here so we'll say inside Constructor we'll say pad service okay first method we'll say public a sync or maybe let's do this go to Services fat service interface and let's copy all these and let's add all these here okay now let me add the method signatures here we'll say public a spring like this now we need to provide bodies for this so for this we can directly use the same method so we'll say a wait pad service. getet all pad sync for this one we'll say a wait pad service dot get newly added pading and this needs count so we use [Music] count here we'll say a pet service. getet pet details say sync with Pat ID here we'll say a wait Pat service dot get popular pets async pass count and then random upore P service dot get random Pat sync with discount cool now we need to define the HTTP verbs and URLs for this so first AP SL controllers is there so AP SL pads will be there and after that for All Pets we'll just add HTTP get with default with blank so the URL for this is going to be API SL pads that's all then we have newly added pads so for this we'll say HTT get HTTP get and the URL we'll use let's say newly added right so we can say new and then the count we could have it as a as a query string which is default or we can have it as a part of URL so let's have it as a part of URL we'll have it in here like this the URL for this is going to be API SL new sorry pads SL new SL some number let's say five let me copy this go to the next one pad details will come here but before that let's go to popular replace this to popular popular so it should be [Music] pads pads PS PS okay and after that random for random we'll say pads slash random and SL then come cool so on this one the pad details let's move it to the very end H here we'll say HTTP get but here we will directly have our Pat ID like this so the URL would become API pets and then pet ID which could be anything this one is Dynamic Pet ID okay so looks like this patch controller is also done let's move it to its separate class so subate file move type to P controller good now we have this users controller now we'll add our methods which are related to this users control okay so here let's inject the user pad service I user pad service so we'll say user pad service user P service go to pets controller it should be I service service service good okay now we have added authorized so we need to have access to the user current user and that we'll need almost in all the action method so in order to get this let's create a private property here so we'll say private in user ID okay and we'll use okay we we'll have private and user ID this should be convert. 2 in32 and here we will have user do claims this is provided by controller base API controllers basically from claims we are going to find the first claim we'll say first and see. type claim type is going to be claim types do name identifier this is the user ID dot value we have user ID we are converting it to in32 and then we are assigning it to this user ID property and now we can access this user ID so if you're wondering from where we are getting this so if you remember we had Au controller from that we have Au service in AU service when we are logging in or registering a user we generating a token that is calling the generate JWT method and in here we have this claim types. name identifier we are adding user ID to name identifier so when we'll fetch the claim value of this name identifier claim we will get access to this user ID which we have here now whenever we'll try to access this this is a computer property it is going to compute this thing so when we say compute it is going to get claims it is going to get the first claim of type name identifier then it is going to convert it to in 30 so what we can do we can have a private nullable field here underscore user ID like this and then we can do we can say or maybe we will have only we will access this once for one action method right so we could we should if that is going to be used accessed multiple times we could have that backing field and then we can check if that is null get this if that is not null directly return that okay in here we are going to have all the methods which we have let's say in I user pad service so let's go there copy all these come here add this so we'll add public a sync and this time we don't need this user ID in all these uh signatures that's because we are going to get access of this user ID from the claims using this user ID property which we just defined so we are going to remove all these user ites cool so first we have adop pync for this we'll say user P service do adop Pat is sync user ID which we have this property user ID and then pet ID pet ID and we are both great it should be out created get user adoptions same thing AIT user P service doget user adoptions async user ID then user favorities a wa to user pad service user pad service dot get user fabor is user ID cool then we have this toggle fa asnc here we'll say AIT user pad service toggle fa sync user ID and Pat ID cool now we just need to define the HTTP verbs and URLs okay so first one adopt pet this is going to be post request restv post and we'll append to this the URL is going to be API sluser and then we will add something to this and that something is going to be adopt and then we could have pet ID here like this so the URL for this will be API SL user SL adopt slash one this is pet ID Vis okay then comes get user adoptions this is going to be in get request and which we could say adoptions so it will be API SL users SL adoptions like this then get user faity so it will also going to be get request let's say fav is the URL will be API SL user SL favorities okay after this we have toggle fabes this is going to be the a post request so here we'll say HTTP post and the URL is going to be favor is slash now we we are going to have a pat ID like this the URL for this would be API SL user SL fa SL F ID which could be anything cool so I guess we are done with these changes as well so let's move this user controller to its own file great now we have these three controllers so so I think we are done with all the changes in our API project now after this we are not going to use uh we are going to use this directly without any change let's try to run this API project and we'll see the Swagger documentation and we'll check if uh we got everything in the documentation and we can get the data okay apply migrations continue and this came here we have some problems respon status is 500 what is the issue refresh 500 swag. Jon it says conflicting method path combination get new SL count for actions get newly added and get random so we have problem in our controller pads new popular this should be random tool save and run okay continue and this time we got okay so we have the we have these three Au controller with API o login API register then we have pads user and everything okay now let's check first let's try to get all the pads so we can try it out execute we have some issue which is saying iPad service is not registered yes so our program. CS we have registered these direct concrete services we should have registered these with interfaces like this iot service token service I don't have interface for token service right service token service token Services directory I don't have interface for that but I have interfaces for other services so cool we are good remove this breakpoint we don't need this breako run [Music] and we have it here cool now let's go to API pads try it out execute and boom successful data we have this data in a sending order ID 35 34 33 and we have this complete data that means API is working controller is working service is working our database is working migrations were successful U ful that's why we are getting this data let's check some random write out let's say two random pets execute we have 19 and 1 try it again 1917 try it again 1528 so we are getting random P now if you go to this user we are not going to get the data the reason is 500 no Authentication scheme was specified and there was no default challenge scheme okay so that is the missing piece we need to add we have added the token service we have added everything but we have not enabled authentication cool so let's go to our program. CS file we need to add authentication first so let's add it somewhere so we'll say Builder do services. add Authentication okay inside this we are going to add some options options are going to be options dot default authentication scheme because we are using JWT we can say jwtb defaults do authentication scheme so this is a constant which is [Music] there okay and let's what is the issue here okay like this and let's add default challenge scheme as well with the same JWT BR default authentication SC cool after this we have added the default authentication then we need to add add JWT BL here we we will add JWT uh where is JWT BR options so let's say JWT options options so using this the system is going to validate our token okay so here we will say that JWT options dot token validation parameters we need to pass this token validation parameters so so using those values it will try to validate the token for authenticated requests so for this I have this in a token Service as a static method get token validation parameter and it needs configuration object this we can say Builder do configuration like this because this is single line we can directly have it inside this here I have this this cool so we have added the authentication now let's use it so before authorization let's say app do use authentication use authentication cool save everything and we should be good now let's run it let's first check the random if initial the things which were working earlier are working still working execute and yes Anonymous request are working fine and now let's go to adoptions authenticated request try it out execute now we can see response status is 401 because we have not provided user authentication user token cool now we need to use this login and register calls so I think API is working we should be good with this one now after this we will start working on our mobile app or Maui app so it was a lot of code it took a lot of time to set up this API but it is set up for good now we'll directly going to consume it and we will work entirely in the mobile Maui side cool I'm going to take a quick break all right so for mobile app let me close everything so close all and in Mobile project first let's install new get packages so we are going to use Community toolkit Maui and Community toolkit mvvm packages so let's install both of them community toolkit. Mai install Okay accept cool and then Community toolkit mvvm this one install apply accept did it get installed yes okay cool save everything now let's go to May program and in here we'll say dot use community community to Kit what was that read me use Maui Community toolkit so use Maui Community toolkit like this cool save everything now if you remember I showed you that I have added different fonts so this U font so we are not going to use open sense so let's modify this so instead of open sense regular we'll say ubu regular and for semi bold we'll say this and let's change the name as well so open sense regular and open sense bold okay and then in uh Styles styles. JL we need to change this so h control h and I'm changing replacing open sense regular with open to regular because this is the font we are using cool and the semi bold that is not here yep okay save now we can delete these to open sense fonts we are not using them closed cool save after this let's start adding the folders which we are going to use in our application so first we'll have pages and this is going to have all the pages the screens main screens we are going to have then we'll have some reusable controls after that we'll have models and after that we are going to have our view models view models like this okay and then we are going to have Services Services cool in Pages let's add all the pages we are going to need for our app so new net Maui net Mai content page JL okay so first we will have our homepage okay then after homepage we will have our first we'll have our on boarding page on boarding page after onboarding we will have our login register page so we are going to use the same page for both login and registrations so login register page after that we will have homepage that I already added then we'll have all pads page cool then I'm going to have our fav page then we'll have profile page profile page okay and then we are going to have a pet Details page let's call it detail sales page after that new item and user adoptions page so let's say adoptions page I think that's all the pages we are going to need in our app okay okay okay okay cool now inside this main page so this is the first page which gets uh loaded when the app starts for the first time so inside this page we are going to have our logic and that logic is going to be first let's clear everything from this page we don't need anything inside this let's remove this remove this remove this so in this we will simply have a logic which will check if this is the first time user is opening the app or uh it is not the first time basically if user is opening the app for the first time we will display onboarding page and if that's not the case we will open homage okay so for this save everything and in here we'll say we are going to override on appearing method okay inside this before that let's go to main page and on main page we will have simple grid inside grid we are going to have activity indicator with vertical options at Center and horizontal options at Center and is running to true so that if it comes to this page we will show the that activity indicator that loading screen only and that color we are going to use static resource primary color like this like this okay cool H in main page here we need to check check if on boarding screen shown okay so we need to somehow store some flag which will tell us that we that we have already uh shown the onboarding screen or no right so for that we can use preferences API so preferences. default dot we can check if we have some key and that key is going to be some magic string so instead of using the magic string directly what we are going to do inside this mobile project on the root only let's create a class and and we will call it UI constants and we'll say public static class UI constant and inside this we'll use public const string we'll say onboarding shown and the value could be anything boarding shown like this clean and we should should be good now so here we will check UI UI constants dot onboarding shown if we already have shown onboarding then we'll say await shell do current. go to async and this is going to be name of name of homepage homepage so this okay and if that's not the case user is opening this for the first time in that case we will rir user to onboarding screen onboarding page like this cool so save everything great after this what we need to do first let's go to app shell and there Define the pages what I mean is we'll create our uh what we call our tab bar and we'll register these top level Pages top level pages are the pages we can display using this double slash so that these are the main P these are not the Stacked navigation Pages which have those back buttons so these are not those pages these are main top level Pages Global pages okay so we need to register this first home main page so let's this is the main page so it is going to be the first page in the list we don't need to change anything here after that we will have shell content and now we need to register our other Pages first let's say title on boarding and we are not going to have anything on on boarding let's have it here we'll say it then the content template so here onboarding pages on all other pages are in Pages folder so we need to add a name space for this first so in here we'll say xmlns Pages equals pages and then in here we could say data template and then Pages onboarding page this is the next page cool on this page this onboarding page first set the route which will be name of the page onboarding page like this and then on this page we will say shell dot nbar is visible false we are not going to show n Bar and we are not going to show tab bar so tab bar is visible also false so na bar and tab bar we don't want these on this on boarding page cool now same thing we'll do for our login registration page so here we'll say login register page and the route is going to be login register page and title there's no point of having this title because we said shell nbar do is visible false so this is not going to be shown in any way so we can remove it or we can directly remove this title all together okay after this these two pages these three pages actually are are the pages which are outside of our tab bar all other pages will fall inside the tab bar so we are going to wrap all other pages in tab bar and in here we are going to add our tabs first let's say homepage so for homepage we'll say homepage route is going to be homepage and homage tab bar is visible no we need to remove it because we want tab bar so the default value for tab bar is visible is true so tab bar is going to be visible and on this we don't want Navar yeah maybe or let's remove it from here we'll add it uh on page label itself okay I think fine let's add the home cool so after home title let's add icon for this so for this I have already added icons so this will be home let's run the app and we'll see the design in real time so that we will see the uh the tabs when we are adding those run it it is going to take some time because it is building the app for the first time okay so the app is here so first let's uh comment these three things I just want to show that this tab bar we are going to uncomment this for sure let's copy this shell content add it again we can see this so the second tab is going to be all pets and it is going to be all pads page route all pads and the icon we are going to use is list great next let me copy two more times third one is going to be our favorite pets so we'll say favorite is favorite page this and the icon is going to be heart heart then last one it is going to be profile icon I guess user yes and this is going to be profile page copy paste and everything is fine now we can see all these all pads favorities profile so this is working great cool now let's uncomment these save so by default this first page main page is going to be displayed and on main page we have a logic which says if we have already shown on boarding go to homepage and if we have not shown on boarding then we should go to to onboarding page in this case we have not shown it we are not adding this key to the preferences so it will always go to this lse case and lse case means it is going to this onboarding page so let's go to onboarding page this is the first page we need to design let's rerun it and we'll start designing this page okay so we are here let's see if this is the correct page yes cool so first thing let's remove this vertical stack layout everything from this page remove everything we don't need this title on this page we will have a grid with row definition as star and star we'll have two rows on this page save in the first row we are going to have an that image rounded Corner image and for rounded Corners we are going to use border so we'll say border grade. row0 which is default and here we'll say stroke shape it is going to be round rectangle and 150 radius if we do this save this we can see something right okay now we'll have height and width which is going to be double of this 150 so we'll say 300 height and 300 width so that we can see A Perfect Circle cool after this stroke shape let's say stroke thickness 10 and then we'll say stroke color which we are going to use static resource our main primary color this one cool okay then we'll say vertical option Center and horizontal option Center for edge cases everything looks fine cool now inside this inside this border we are going to have an image the source is going to be I have this image in our resources folder so img22 jpg this is the image this this one cool and on this image Also let's set horizontal option Center vertical option Center aspect fill and then height and width same as we have on its container so we'll say height 300 and width 300 like this save everything great now let's have some Shadow so for the shadow we are going to have the Shadow on Border only so we'll say border do Shadow and inside this Shadow let's have the color of Shadow so we'll say brush and we are going to use the main color we are using which is this primary color like this okay we can see something let's increase it so we'll say radius and 250 cool we can see this thing great save everything now let's start working on the second part where we are going to add some text so after this border we are going to have a grid with cre do Row one and inside this we are going to have two rows so row definitions first star second Auto so the second one we are going to have one our button which is that get started button which will navigate us to the next page and the first section we are going to have whatever uh space is remaining it should take the first row okay now inside this let's have some padding of let's say 15 tool inside this we will have a vertical stack layout so this will be grid. row z0 and we are going to have some spacing of around 30 inside this we are going to have a label with some text and the text is going to be find your find find your favorite friend close to you and we can see this cool now let's add some styling to this label so first we'll say font size 40 cool then we'll say font attributes Bard okay then we'll have line height to This 1.2 okay that's all I guess now let's add one more more label for the second label we are going to have a long text a small description kind of text and for this we don't need this to be bold then the font size it should be smaller font size somewhat around 18 okay and line height is fine 1.2 or maybe we can increase it a bit 1.3 this is fine one more thing I want to do on this we'll say horizontal text alignment to Center so everything moves to Center save and we are good with this great now let's have a button so we'll say button and this is going to be Row one text is going to be explore let's see how it looks it looks great let's add some styling so first we'll add some no pad we don't need padding let's have the default padding we can increase Corner radius let's in have it to 12 and yes let's increase the padding so from left right we are good Zero from top and bottom we need 15 cool after this let's increase font size a bit so we'll say font size 20 and then font attributes bold bold okay cool save everything and now we are good good it looks great okay now when we tap on this explore but before that we have shown this page right if we have shown this page we should add that to if we go to our main page we are checking this constant in our preferences so when we have shown this onboarding page we should uh add this key to our uh preferences that we have shown this thing so for this what we are going to do inside it Constructor only we'll say preferences dot default do set the key key is going to be U constants dot onboarding shown and the value it could be anything so let's have some string do empty we are not using its value we are just checking if this key exists right so we this key exist now and we are good cool and when we click on this explore page m before this we should let's remove this uh this top uh status bar this is this default blue color but we want our this color our primary color so for this thing what we'll do we'll go to our app shell we need that uh Global level on complete app level so here what we'll do we'll add a name space first so we'll say XML NS toolkit so here we'll say Maui toolkit this one and then we'll say shell dot behaviors and here we'll say status bar Behavior and the status bar color we will get it from static resource primary like this and then the text content is light which is good but let's add it status bar style light content and save everything cool now we have this thing so we are good with this now when we tap on this explore it should move to the next page and when we are going from here so next page should be our login register page that should be default okay so on boarding on boarding where is zaml here on this button let's add a clicked event like this save everything B and click let's go here and here we'll simply say a shell. current. go to async and we'll move to the name of login register page like this like this save everything and we are good now okay so let me stop the app and run it again so that we can see this page right now when I'm running it should display the onboarding page because right now we do not have that key set that UI constants this key on boarding shown okay output app is loading and we are on onboarding screen we tap on explore now we are on login register page let's see if we are on that page only on this we'll say log register page right yes Save cool now if I rerun the app now it should directly land on homepage no log register page no onboarding page because we have that logic which says that move to homepage if onboarding screen is already shown you see we move to the homepage this time we did not see that onboarding page and that logic we have in here right cool so we'll work on login register page later or maybe let's work on that page first okay let's work on that page so for testing uh to show that login register page let's change this homepage to login register page so that we will be on login register page and then we'll uh design that page okay we are on login register page now let me close all these Pages close all tabs open the login register Pages ZL and code behind on ZL on ZL we don't need this title we are not using this here remove this vertical Stu layout we don't need this here on this page we'll use grid then we'll use row definitions and now we are going to divide our page in five sections so first 40% for the first row and the second 60% is for the second row okay so like this inside this first I'm going to use the same thing I have used [Music] for the onboarding page or maybe let's let's try this border grade. row0 okay and here I'm going to say stroke shape round rectangle same 150 height request 300 width request 300 stroke colors we need stroke is static resource primary and then stroke thickness same stroke thickness same 10 okay okay we can see this inside this we are going to have an image and this time the image is going to be img2.jpg this image cool now let's have some so first on this image we are going to have height and width but before that let's use aspect so we'll say aspect fill then we'll have height let's have 250px and then width also 250 like this let's change these as well 250 and 250 okay cool on this image let's have vertical options as Center and horizontal options cent center great after this we are going to have the same border Shadow so border do Shadow and here we are going to have Shadow with the color which is brush static resource primary and then the radius same 250 cool save everything and we should be good now okay first row is done minimize this now let's start working on the second row for the second row we are going to have one scroll view we'll say grade. Row one the first row and on this let's have a padding of 15 inside this let's have a vertical stack layout okay on this one we'll have some spacing 30 inside this first we'll have a grid with the column definitions star and auto so we'll have two columns First Column will display some text so that is going to be right now I'm hardcoding it to login then we'll make it Dynamic text login let's see how it looks okay so this is going to be gr do column Z which is default then we are going to have one more label and this label grid. column 1 and the text is going to be switch to register like this and cool save everything now let's start designing these buttons sorry these labels so on this text login First let's say font size size 40 okay font attributes bold okay then line height same 1.2 okay then for this second one the switch to register so first thing let's move it to vertically Center okay horizontally and which is in this case looks like default but let's add it after that let's add some padding to this so we'll add padding of five and then we are going to add [Music] some okay I had that setting that BG color right so if I go on resources Styles colors I have this BG color right so this is some very light gray kind of color so on this page login page let's add the background color for entire page here we'll say static resource BG color nice now on this label this switch to register label we'll say background color white okay okay now what else we can do on this one say let's make it B font attributes bold and let's add text decoration underline like this cool okay it looks fine save everything and we are good with this cool after this now we'll start designing our main form so for this inside this main vertical St layout after grid we are going to have one more vertical strike layout with the spacing of let's say 10 okay here we'll have entry control so entry placeholder is going to be enter name for login we don't need name but I'm adding it then I'll set to its visibility I'll modify its visibility but for now let's see how it looks enter name this is fine let's change the placeholder color so placeholder color and this we are going to have static resource primary color like this okay fine let me copy this two times first name then we'll have email and then we'll have password okay save everything for email the second one we'll say keyboard it should be email keyboard and for the last one this password we'll say is password to true because this should be password and move save everything now if we remove this we can see name email and password so this looks fine for login we don't need name that I'll modify it later but for now I'm just focusing on Design This is fine cool after all these entries let's have our buttons so after entry let's have button not insert this so for button we will have a text and then text is going to be let's say login we save it we can see this login cool on this button we are going to have the same design which we had on onboarding so let's do this let's create one style um on global level so we'll go to Styles styles. ZL we can edit here or maybe we can addit In app. zaml Here Also we can add but let's add it in Styles only so we'll say at the very and we'll say style target type uh button and here we'll say x key and this key is going to be let say BTN only or maybe BTN primary okay and here we are going to have couple of seter properties so seter property and value save now let's go to our button and let's we will have first we'll have padding of 0 and 15 so padding value is going to be 015 let's copy it couple time then Corner radius 12 so Corner radius 12 and then font attributes bold font attributes bold and then font size 20 font size 20 save everything we are good from onboarding we can remove all these remove this remove these three fine and here we can add style static resource BN primary save and go back to our login register page save everything open it and here we will add the same style so we'll say style static resource bet in primary and save and we can see the same design great okay now after this vertical stack layout let's have we need to have that skip button right so for that uh I'll have some line and then Skip and then line so for that what I'm going to use I'm going to to use a grid with column definitions I'll say Star Auto and star inside this first I'm going to have a box view box view so gr do column column zero okay and then height request height request let's say one and then color is going to be our main primary color static resource primary if I do this I can see this great after this let's copy this paste it one more time and this should be grid. column 2 save okay and between these I'm going to have a button with the grade do column 1 and the text is going to be let's say skip for now like this cool we just need to make this button smaller okay so for this what I'll do I'll say padding first let's say horizontal options say Center it will move it to Center then we'll say padding and from left and right let's say 25 and from top and bottom let's say five okay and then let's have a fixed height of 30 cool okay it looks fine if you want some spacing between these we on this grid we can say column spacing and let's have five and cool we are good with this okay it is fine everything looks great on this page we will work on this the functionality interactivity after some time so it looks great cool so let's work on interactivity then for this what we will do we need uh that view model now we'll start working on the main view models okay so login register view model let's go to view models okay so for login register page before creating view model let's create a model so in here we'll say login register model okay and this is going to be an observable object so let's say public partial class login register model and here we'll say observable observable object which should come from Community toolkit mvvm component model cool inside this we will have three properties and because all these properties are going to be observable properties so we will use this private string and name we'll decorate with observable property then second one we'll have for yeah for password we need and one for email email and all these three are going to be observable property observable property Cool okay now in this we can have uh some helper properties which we can use so one property I need is going to be public bu is new user so new user is going to have name this this property uh what I mean by new user is when user is trying to register that means it's a new user so here we'll check if is new user right so it should be not string do is null or white space name if name is not null or white space that means this is a new user case this is a registration case cool after this I'm going to have one method here public void validate or we can have this as a property public bull we'll say is valid this is going to be get only and here we will apply our logic and that logic is going to be first we will check if string do is null or white space email or string dot is null or wh space password if any of these is null or empty or wh space we know these two fields are required for both the cases login and registration for both cases from here we will simply return return false after this we will check if if this is new user case new user we have this name right but what if we do not have name no okay we should have this as a method so we'll say validate and we will get one parameter here which will be is register ation mode H I'll tell you why this is required this is in my mind okay so now we will check if this is registration mode and the name property is null or empty if this is registration mode we should have some value in this name so if this is registration mode and we do not have any value for name this is an invalid State and after this we'll say return true because now this is a valid State cool so now our model is ready now let's go to view models and here we are going to create a class for our view model here we'll say login register view model like this okay so this is going to be public partial because this is again going to be an observable object observable rable object cool now in here we will have a property private bu is registration mode and this is going to be an observable property you remember when we are working we have that switch to login switch to registration that label that button so it will that functionality will be handled by this is registration mode okay after this we are going to have our model so private login registration model uh let's call it model only and this is going to be an observable property like this and I think we are good with this okay let's add the methods so first we will have if you are following me I follow one approach in almost all our view models we have an initialize method initialize method so here we are going to set uh registration mode to true but it should be true only when we are coming for the first time from our uh what is that onboarding page so we need to have some state which will uh handle that if this is the first time we are coming to this page so for this what we should have we should have a property here so private bu is first time and this is going to be observable property observable property and this we are going to have it as a shell navigation parameter so query parameter here we will decorate our view model with query property and the name we are going to use this is first time and the query ID same is first time is first time like this cool now we have this property Set uh what is Theo this is Theo okay now in initialize we will check if uh let's make it a label so that we don't force it from inside our app from our profile page we can come to login again right so at that time we are not going to pass any value for this so it will be null in that case so here we'll check if this first case do has value uh is first time do has value and first time dot value is true if that's the case we will set each registration mode to True else the default value for registration mode is false so we are good with this initial setup cool after this we are going to have couple of commands the first command is going to be uh that toggle the switch to registration and switch to login mode so here we'll say private void let's say toggle mode inside this we will simply set is registration mode equals not is registration mode so opposite of each registration mode so if this was true we'll set it false and if it was false we'll set it true and now because this is a command we will decorate it with relay command like this cool after this we are going to have one method so we have that skip for now button right so for this let's add a command private faing task and we'll say skip skip for now like this and from here what we should do we should simply say await shell do current dot go to async and from skip for now we will redirect user directly to homepage homepage like this and this is again going to be in relay command save everything cool after this now we'll have one command for our submit case so login register case so here we'll say private asnc task and let's say submit and this is again going to be in relay command relay command fine now we'll add our validation logic first so here we'll say if login registration model not this model this model dot validate and here we need to pass that each registration mode so if this is valid we'll continue if this is not valid if this is not valid we need to show some uh message some indicator to user that something is invalid you need to validate it for this what we'll do we will use uh Community toolkit Maui Community toolkit to show our error toast message here we'll say toast no no no not from Android we'll say from Community toolkit Maui toast do make and the message the message is going to be let's have this all fields are mandat cool do show okay and then just return from here don't execute forther logic we are good with this cool if this was not the case we are going to we should have some private bu is buy and this is going to be observable property again and now we will set this ISB to True like this and then we'll use we'll make the make API call to login register user login or register user okay for now what I'm here having here let's have a some manual delay of let's say yeah one second is fine of 1 second and when this is fine after this that mean if the request was successful in this case let's assume the request is successful we need to navigate user to the next next page okay so in this case we will navigate user to the homepage and we can directly call this skip for now method because it is navigating user to the homepage only here we can say await skip for now this method and after that let's say is video to false and everything seems good okay let's clean this up now first thing I would do is let's add a global usings file so that we can add all those these usings to Global so that we don't have to rewrite these again and again so on this Maui project let me create a class we'll say Global using the name is up to you you can name it whatever you want it does not matter only thing which matters is all all the using statements should be prefixed with global global using and this that's all and you don't need to create a new class file for this we could have this inside this also it will be complete application label but it's always a good idea to have these separated so that we know all the global usings live inside This Global usings we have models Pages input this let's add one for view models fine we'll keep on adding others whenever we need them right now you see we don't need any of these so we can clean this up great and if you go to models here also we should not be using this component model we don't need this okay so looks like this view model is fine now we need to use this view model in our app so for this let's go to our Pages login register page zl. CS file and here we'll add this view model so let's call it view model view model cool and now we'll override a method over right on appearing and in here we'll call view model do initialize method like this tool and then on this page we'll set the it space binding context to view model so that we can use it corly save everything and now we are good so first let's add the name space for our view models here so we'll say xmlns let's call it view model so view models and let's add one more for models I don't know if we will need this on this or no but let's add it so we'll say this models okay fine save everything after this let's add the Set uh data type for this page the data type is going to be login register G like this save everything fine now it should work the only thing is we are injecting this login register view model inside this login register page so we need to add this to our dependency container what we'll do let's come here on Maui program and let's create one method here we'll say static void register services or maybe what we should do Register App dependency something like this and here we'll have service collection services and we are good and from here we are going to call this register app dependencies builder do services like this and we are good now inside this method we are going to add all our uh all our registrations so first let's say services. add this login register view model so we'll add it as transient this is going to be login register view model and with this we'll add our uh page login register page login regist is like this and we are good registration is done now we can run our app and then we'll start adding interactivity to our login register page where is this s this cool so let's or maybe before that let's do this inside this grid we have that hbz flag so let's have some uh that activity indicator to display that loader here here we'll say Activity indicator and vertical options Center horizontal options Center and we'll say I'm not setting any grid row or column anything so it will be always after all these that means it will be on top here we'll say if is running we are going to bind it with the isbg property like this and after is running uh let's have the color which will be our static resource primary color and then let's have height and width so something like 30 he request and width request is also 30 so save everything now let's run the app okay app is here let's start working so first thing this login word it should be handled by that each registration mode property so let's go to this scroll view we have this login right hardcoded login value what we'll do we'll add triggers here so label do triggers here we are going to have a data trigger with Target type label and on this binding should be binding is registration mode okay and it should trigger when the value is we could handle with true or false anyone any so if each registration mod true let's use this if this is true then we'll say Setter and the property is going to be text and the value is going to be register like this so by default Valu is login and this trigger will trigger whenever each registration Mode's value is true so if its value is true it will add this text to register and if if that's not the case it will fall back to the default value which is login so this is fine now let's add the toggle mode logic to this switch to register and the same thing this trigger should be on this as well because right now it says switch to register and when we'll be on registration page then it should say switch to login so let me copy this trigger from the first label and we'll add it to the second label like this and this time we will make it Opposite so the default value is switch to register and when each registration mov true we should say switch to login save right now there is no change now whenever we tap on this label fwit to register it should toggle the mode let's do this on this label we will add AJ recognizer T Dash recognizer and on this we'll use a command and we'll use binding and here we will have toggle mode command like this save everything now let's try it so you see right now this is a default case if I tap on switch to register the heading changeed to register and this labels text changeed to switch to login if I go there so that means this functionality is working now we need to have two more things with this toggle mode so first this login text button this should also change with this change so if we are on registration page this buttons text should show register else it should show login which is the default so what I'm going to do I'm going to copy this data trigger or maybe the First Data trigger so we can use it directly let's go to our login button and that is where is it this is the 18 186 on this button we'll use the same thing we'll say button dot triggers add this and the DAT Target type is going to be button for this one so if registration mode is true it will the text should say register else it will say true uh that login which is the default so save everything and now we can see register login register so the tax is changing cool and there is one more thing with this toggle mode this name field this should come only if we are in register mode in registration mode right so let's go to this name field we have have it here so on this one again we are going to add uh no not trigger on this we can have this is visible property and we'll bind it to P registration mode so if registration mode is true then it should be visible if registration mode is false it should be hidden so if we check you see if we switch to login then we don't have that name field and if we switch to register then we have the name so all these three things are in sync now we can start working cool now on skip for now let's add our other commands so on skip for now this is the button so we'll add our Command and here we'll say uh binding es skip for Now command like this save now if we tab on the skip for now it went directly to homepage now if we go back we are out so let's run the app again okay we are on login mode now let's add the command on this login register button so there this button is here on this button let's add a command command this should be binding submit command so save everything cool and now if we tap on this login we have an error which says object reference not set to an instance of an object and do let me me know in the comment if you can think of what the issue is here okay so for me I'll go to view model view model and we do not have any default Valu for this so this is null and when we tapped on that submit command it came here and tried to validate on this model which is null so we should have a default value for this save and just now I got that we have one more missing piece that missing piece is on this entry uh controls we should bind the text so this is the name so here we'll say model do name let's bind others as well so on email we'll bind it to email and on password we'll bind it with password like this so save everything and before running it let's use that is first where is it this is first time let's use this one as well so this should come from the onboarding page so if we go to onboarding page we were pass we will navigating to this login registration mode so here we will add the parameter so we have two approaches either we can have it as that dictionary parameters dictionary or because this is a simple value we can use directly here with question mark name of login register view model dot is first time this is the key name and the value name is going value is going to be true like this okay so save everything now this because we already have this onboarding shown preference set so what we'll do let's uninstall the app then it will remove this thing and then we can see the onboarding screen again and when we'll tap on that explore button it will go to the login regist mode with this is first time to set to True okay so let me uninstall the app first and then I'm going to run the app all right I uninstalled it and I run it now we are on this onboarding page now we if we tap on explore we have error which says invalid cost exception invalid cast from system. string to NB Boolean and which is fine let's do this instead of using this approach it should be good with primitive uh not primitive maybe string values so what we'll do here we'll create a parameters parameters variable here and here we'll say new dictionary with string and object which is the required uh format for parameters so here first We'll add our key which is going to be this how login register view model. first time and the value is going to be true cool so now after this login registration page parameter we'll say comma bu animate or parameters so here we'll pass our parameters like this save and let me uninstall the app again so that we can see that on boarding screen okay let's run it the device okay okay so you can see this we'll tape on explore still there is some value invalid cast for system. Boolean to system. private Cod there is some cast for system. Boolean to system. nullable Boolean what is say is let's check if we are missing something we have n Lael Boolean on here so we are good each first time we have n lab Boolean so it cannot set Boolean to nullable Boolean it is strange because the other way around I can think of it cannot set Boolean uh label Boolean value to Boolean value from system. Boolean to Boolean is this H let's see let me check what the issue is let's make it non nullable then we'll see it first time now we can remove all this it should be just if first time is registration mode true let's see if this works and we again need to to uninstall that app uninstalled okay okay Run Okay AB here explore and we came here but it did not set this is first time property to true and why so qu property is first time is first time onboarding is first time to true and we are using this parameter there is some issue let me debug it everything seems to be right I don't know what the issue is do let me in the comment if you know what the issue is or if I'm missing something somewhere where my might be some very small mistake I'm just trying to debug and you can pause this video and write a comment if you know what the issue is okay all right so were you able to figure out what the issue was for me I tried so many things but it is not working in the same way so I just want to show you something if I run this app again if I click on explore this is fine let's continue on appearing let's continue this time it came to login register view models initialize method at this time this is first time is false even though we first passed through from the uh the previous page now if you continue because this was not like this now if we press this login it came here at this time we check we have this is first time value set to true that means it is setting this query property to the value which we are passing from previous page but it is not set at the time when this this initialized method is being called This is being called from this own appearing so at this point of time it does not set the query property we have another method which is override on navigator to in this also I Tred to add this inside this method and at this point of time also it it was not setting its value so right now I don't think we have some direct method or something that uh that can guarantee that right at this point of time all the query properties are set so what we are going to do in order to work uh the way we are expecting it whenever we are using any observable property for example this is first time and all these so it this community toolkit mvvm it creates some helper property and methods so if I go to this is first time F12 now it is here in this generated file so it's first time now if we check before setting its value it is calling these methods on is first time changing with the value then on is first time changing with default and values then after changing it then it is Raising this one property changing after that it changes the value then again it calls these three methods on first time changed with the single parameter and two parameters this is old value and this is new value and then this property change all these events and these methods will be for all the properties this community toolkit is generating for example if we go to is busy then we have on is busy changing on is busy changing second overload method then after changing the value it is calling on B changed the same methods now if you go to any of the implementation of this if we go here we have this partial void on is first time changed and there is no body for this method so these are hooks which this community toolkit is providing so it is calling these so we can add our logic our code whenever something is changing or something is happening inside this so these methods these partial methods this is not partial class this is partial method so partial methods are basically for uh implementing hooks hook points so it is created that hooko or we are going to provide body for this method that will be called whenever this method is being called this method is being called right before the is first uh uh Time Properties being changed okay so what I'm going to do in our login register view model model log with Mr view here what we'll do we'll say partial and now we can see all the partial methods so we have this on is first time changed or on is first time change changing changing we need this one now we can provide body here and this method is going to be called from the community toolkits whenever it is setting this first time property okay so now we can remove this and this logic we can cut this logic from here and add it here and now there is no point of having this initialized method in this particular case so we can remove this then from the login register page here we can simply remove this on appearing allog together remove it save it and stop stop save everything and now we should be good so using this whenever we will first come to the uh whenever we'll first come to this page from onboarding screen we are setting this AG first time and when this is being set we will set age registration mode to true and then it should automatically open registration page for the first time cool so let's try it out now okay app is here now if I press explore continue and and it did not work now am I missing something let's go there let's add the break point here full value is first time oh my bad my bad this is on is first time changing that means before changing the value right so we have two approaches either we can use changed method or or if we are not willing to use changed method then we can simply use this value W value which is the value it is going to set so we can use this one save and now it should work okay it's coming explore continue and this time we came here value should be true continue and we are on register page register mode basically we can switch around and everything will work same we can tap login it came to submit continue continue and we can see that this toast message cool so looks like I everything is working great okay do we said that is busy yes we said that is busy is busy is busy let's add values login and we can see this activity indicator okay so that means everything is working there a skip for now any skip for now we are going here cool now let's do one thing before continuing further what we'll do so this is busy then this go to a sync method on shell do current and this toast message these are the things which will be uh used in almost all the pages that means in almost all the view models so instead of repeating all these things what we can do we can simply create all these thing in a centralized place and all the view models can use that centralized place so that centralized place is going to be in base class for all the view models so what I mean is in view models I'm going to create a new class which will be base view model so base view model okay and this is going to be public partial class with observable object as its Base Class so that it is using Community toolkit mbbm now and in here first thing let's cut this private bu is busy property add it here great save everything and now this file this is going to be inherited from base view mod save everything and we should be good now cool now let's do methods add methods for these as well so this is for go to async so we'll say uh we can have protected a sync task go to a sync like this remove this okay add this add this shell. current. go to async because this is a single line so we can use expression body like this and this thing is going to be a dynamic part so let's use all the flavors of this goto a sync so we have 1 2 3 four states right so let's use all these four in here remove all these description summary so remove remove cool now we are going to use this so first one is this navigation state so let's add it here and we can directly use it here like this first method is ready then we'll do the other methods second method is going to be this one state and animate so let's do this state comma animate like this missing then third one is going to be with State and parameters the state and parameters and then the last one it is going to be with State animate and parameters so we have all the overloaded methods of this Define in here so we can directly use these now in our child view models derived view models cool after go to a sync we had that toast this toast message is right so this is also a thing which will be used on almost on all the pages so we'll use this here so we'll say protected async task we'll say to toast async string message and here we are going to say await toast. make with this message and then show let's change all these public to protected cool okay toast is fine and at the same time let's add the alert as well we might need alert so here we'll say show alert I think and here we are going to use uh the app do current dot main page Dot display alert this one title message cancel button okay so let's use this in this so string title title string message and then string button text and here we'll say title message and the incomes button text okay okay and we might need a confirm box as well for that also let's use task bu and we'll say show confirm async confirm async and we'll use the same display alert it has other overloaded methods so this one which returns bullion and it gets title message and then two buttons accept button and cancel button so here we'll say accept button we'll say Okay button text and then we'll have second one we'll say cancel button text so here we'll say Okay button text which is accept button for this and then we will have this cancel which is a cancel button text like this and now our all our methods are ready to be used cool let's use this so in base view model we have used we have removed is busy from here but we are still using it inside submit method that means this thing is working then for skip for now let's directly use go to a sync it is coming from Bas view model then for this toast. make show we'll say show to a sync and then we are going to directly use this message here like this cool so we are good now great okay now on onboarding screen I have commented out this thing because we were working on that login screen we wanted that login screen to come sorry that onboarding screen to display every time so that we can tap on that explore button and it can go to the login register page for the first time now I'm uncommenting it and let's run it everything should work same as it was working before okay so the app is here let's explore oh my god let's remove this break point continue and now we are on register mode login register switching working on register we are here this thing enter password register okay continue continue and we can see that and now we are on home page so that means this functionality is working right now this is not talking to API not yet we will add that functionality but for now this is R okay now I am thinking should we Implement API consumption first or we should design our uh UI first then we should go there H okay so let's Implement uh API consumption part here so in this project we are going to use we are not going to use uh stdb client or sttp client Factory directly we are going to use refit refit client to make our sttp API calls so how to use Rapid client and what rapid client is I have already created a video for this where I explained everything in detail and in that video I showed you how can we use refid client to connect to Local Host API but in this video I'm going to show you a different way we are going to use dep tunnels the reason being we are using some images right and using sttp client and sttp client Factory we can uh make the HTTP calls from emulator but it does not work for images the reason is the images when we uh show an any image in our mobile app using that image control we directly set that image source and if that source is in url it is going to hit that URL and if our API is hosted on Local Host then that image source that call is not routing through our HTTP uh client or HTTP client Factory or that HTTP message Handler which we have created it does not go through that route it is not going to figure out that where this Local Host is so we will not be able to display images from Local Host in our mobile app ined Maui uh this Android emulator or iOS emulator same thing goes with local device if we have our local device in this demo if you uh saw when I was showing the demo I showed you how can we use uh our local device and the local device was also using the same data everything so if we use local device then that Local Host API that is not going to work for sure because then Local Host and that 1022 that does not exist there so because of these two things we are going to use a different approach and maybe before using rid let me show you that approach so this API our API project we are going to run this API project using Dev tunnels so what da tunnel is it is a feature which latest Visual Studio gives us whenever we are trying to uh run our app so if you go to API here we have this da tunnels no active tunnel it requires latest uh visual studio version using this what we can do I already have this test n but I can show you a uh from scratch I'm going to attach the official Microsoft's Link in the description or comment box you can check in detail how Dev tunnel works so here what we can do right now if we run this app it runs on Local Host with that Port which we have defined in our program.cs it runs on https local 755 that is fine so for using Dev tunnels we can go here and here we have this Dev tunnels we can create a tunnel like this we can name it whatever we want so the name is up to us then it we need to uh be logged in into Visual Studio to this to work I'm already logged in so it will work for me here I'll say pet adoption AP YT YouTube okay then comes Tel type temporary and persistent so temporary is if you check whenever we are going to close and open Visual Studio again it will generate a new URL but that is not what we want so we can use persistent so the URL is going to be same that's because we are going to use this URL hardcoded in our mobile app Maui app so we might close Visual Studio a couple of times and then we can open it so we don't want to keep on changing that URL again and again so we'll use persistent okay then comes this access you can read in detail so we can use public for now we are not using uh any sensitive information or things like that so we should be good with this then we can press okay okay now it is going to create a Dev tunnel for us it is creating it takes some time so Dev tunnel has been successfully created and is selected as the currently active tunnel so from here this is selected right now whenever using this when you close visual studio and open it again by default you will have this none so whenever you reopen visual studio just go to this section go to dep tunnel and select your this dep tunnel now what it did for us if we run it now it is going to generate a new URL for us and that URL is going to be a public URL which we can hit from anywhere in the world from any device so let's Let it wait to run okay so looks like this is running API is running it is Al on Local Host but if you go to Output or do we have Dev tunnel somewhere here okay it opened this thing for us so this URL https SX d89 whatever it is Ms this is the URL where our application running right now let's continue we'll continue Swagger UI and the cool part is although it is running in here we can add break points and we can debug our API so if we go to let's say we go to pets so I'm going to add a break point in our let's say controller pads controller and get all pads okay let's add a break point here cool now I'm going to run it from here I'll say API pad try out execute now if I hit this breako got hit so this is a cool part we can actually debug our uh code C even though it is running on da tunnel so this is a cool part now we can use this thing to use uh this URL from any device from your my mobile device from emulator from anywhere we don't need to set up that if you remember uh earlier whenever we wanted to connect to our API from our Maui app if it is on https we had to do a bunch of stuff we need to create platform specific HTTP message handlers for Android and iOS then we need to allow the certificates the https certificate all those stuff using this we don't need to do any of those we can directly use consume this URL and we will be able to use our API directly okay so we are going to use this approach only now let me stop it first and then what we are going to do we will run it in let start without debugging mode but before that we have that URL copied so for for that URL we are going to add it in our constants so and that is going to be used from both the projects so let's go to Shared in shared I'm going to create a new new file new class file and let's call it app constants constants so this is going to be public static class app constants and here we'll say public con string base API URL like this and we'll use this URL directly here great clean everything and we should be good now cool so from API side everything is fine let me uh before that let's now we'll start working on our mobile ma application so first thing we will add a new get package to use refit client so that will be rit. HTTP client Factory graphic. HTTP client Factory byet Foundation contribution so let's installed apply and this is fine what is the issue here okay this is taking something else if we go to the packages refit HTTP C Factory is installed so save everything and we are good now cool now we have installed this now we need to set up this right so in order to set it up we'll go to Mau program and here we are going to create one more method static void we'll say configure rapid like this with I service collection Services same and from here we will call it so configure Rait with Builder do services like this cool now we'll work inside this method only now in order to register refit in order to work with Rait what we can say Services dot we have ADD refit client and then it needs the type and this type is the way we work with our API calls what I mean is in order to use refit for our API calls we will go we will go to Services inside mobile app inside not Maui project we'll go here and here we are going to create a class actually interface we need interfaces and the name is up to us so for example for login and register we are going to use Au uh API so I'll call it i o API like this and I'll make it public public interface I or API now whatever calls we need we can add those as a part of this interface so we'll go to an API o controller here we have two methods one is for login and one is for register so we just need to use this thing this signature go here in here we will just add this signature then let's do this same for register uh like this so this method this method is up to us the name it could be anything we can name it whatever we want the uh parameter type and written type these should match with the API types right so here we'll say register P sync after this there is one more thing if we don't want want to use this API response this is coming from our shared API response refit also provides a API response class we can use that directly like this if you use this this should come from Rait this will not work so we need to do something like this refed do a like this the problem is I also named our response classes API response and Rit also Al has API response so there is a name Clash but we should be good with this cool so using this we have just created interfaces interface now we can configure it now next thing is how it would know that for this method uh what is the API URL it need to connect with so for that Rait provides us some uh attributes those are with the sttp verbs so in our case our login method this is a post method and here we need to provide the URL so if you go to here the URL is API or login this is our API URL for login so here we are going to say API sl/ login like this save everything and let's copy this thing again come here and it should be API or register like this now we are good now our Au API is ready there is one error and now this is the thing I was mentioning that this API response this generic type I have also defined it and refit also has it with the same name AP response and then Dynamic type we have two approaches either we can rename our response or we can use the fully qualified name so we could say here shared dod. AP response so it would know that it is coming from our API like this cool so save everything now I our o API is completed now we'll uh configure this iot API so let's go to my program and we are here and here we can say I API I API like this do I have Global usings here yes right so let's add this as well the global usings so Global usings I have added global using and P Mai mobile. Services cool now we can remove it from here iot API and this is the simplest form to register the or to configure a rid client okay but in our case we need couple of other things as well the first thing is going to be we can set we can configure our HTTP client okay so here we'll say configure HTTP client and HTTP client and we will set the base URL The Base address for our API so here we'll say HTTP client. Base address equals new URI and the Base address we have set it to our app constants constants dot base API URL like this and now a RIT client for this API is done so this is the very simple basic example how can we set this we will keep on adding other things as well when we'll work on the authenticated things or maybe we can work on that one also just right now only okay let's set up this Rait [Music] once okay after all API we have pads controller so let's create interface for that as well so public interface i pads API we'll do this and now we'll go to pads controller and we are going to implement all these methods so let me copy all these from there I'll come here and then I'm just going to modify things I'm going to remove the body because all these methods we'll use so clean this up fine now we are going to change HTTP get HTTP post to direct get and post which will come from rapit so get get get get and then get cool now the URL we know this API pad SL1 so this one is dynamic so we'll say API SL pad SL this we are good here we'll say the same thing like this API pads random then this popular will say API SL uh p/ poopular and then for this one we'll set this and then the first one it would be direct API SL Pats cool now next thing is this API response so we need to use this fully qualified we can add it as uh static uh using as well but so now let's use it like this only and then what is the issue okay because these are in interfaces we don't need public ass and fine now we can remove this commented URL parts now I our pads API is also done let's move it to its separate file move type to iPads API tool now let's register this as well so let's go to Maui program and we are going to copy this same thing paste it one more time and this time we'll say iads API now you see we are repeating this thing configure HTTP client with this so we can exct this out in a method so here we'll say static and this takes an action so it will return void and we'll say set HTTP client or configure HTTP client the name is up to us and it would get HTTP client HTTP client HTTP client and we can simply cut this thing and and add it to the body of this metod like this and then we can directly use this here like this and now we are both okay great now let's use the third one which is this user controller so we are going to create one more interface public interface interface I user maybe just I user API let's go to user controller and copy the methods from here copy and then let's modify the things remove body okay remove public a sync and change this HTTP get and post to direct post and get so post get get and then post after that let's add the complete URLs so here we'll have API user adopt this then this one we'll have API users adoptions then the third one API users fabes and then last one this now we can remove this thing remove remove and then make this API response so single AP response is fine which is defined in our uh code only but this generic one this is the one which rapid defines so we'll make it again fully qualified so we'll say share dto API response share dto API response great let's move this I user API to its own file and now we can go to Mai program and do the same thing for this one as well I user API now all API PS API these are same but but there is one difference in this I user API this user controller so do let me know in the comment if you can guess what is the difference in this user what's different in this user controller okay so let me tell you what the difference is the difference is this authorized attribute on this user controller so all controller and pads controller do not have that attribute that means anyone can access consume these apis all controller API and petch controller API but for user controller API we need to have uh the user authenticated that means in our case we are using JWT token authentication so each and every request which comes to this user controller that should have JWT beor token in its header so right now from our Maui app we have not set that explicitly from anywhere right right now all these are same we do not have any difference in this but somehow we need to add that users uh the V token to this users API so the way we can do this using Rait I already have explained this in detail in the Rait client video which I created so again I'm going to add the link of that in description and comment box so do check that video out in order to do this we have an headers attribute which we can apply on uh interface label or method label so for example let's say in this users API let's say this adopt is the only one which needs that headers explicitly so we'll add it on this only this headers this is not going to to be empty here we'll say authorization colum and then beor like this so right now using this we are saying that you should use you should add this authorization header and that is going to be bearded for this call okay so we can add it on single method level that means API endpoint level or we can add it on interface level which will be applied to all the API calls all the end points which are defined in this interface right now we need this to all these methods which are in this user API so we are going to add it on interface level cool now we are good we have said we we said that you should add this authorization be token but where is the token the actual token value that is not in here we need to tell the Rait that you should get this token value from somewhere and that somewhere is going to be we have this small program here when we are using this add repit client there we have something which is this method it can take RIT settings okay now if we have that rid settings directly we can use that but there is other overload methods as well which will this one the second one here it says it uh the first parameter is fun delegate so here I service provider is input and refit settings is output so we are going to use this method how we are going to use it we s SP which is for service provider now from here we need to return repit setting RIT settings object like this what is the issue new rid settings okay so this is the thing we are going to use but right now we have not set anything so this is the empty rapid settings we have not defined anything now what we'll do we'll Define something and that something is refit has a property which which is authorization header value getter if you see this is a funk Funk delegate which has two input parameters sttp request message cancellation token and then it returns one task of string which is going to be our token so we're going to Define it but in our case we are not going to use HTTP request message and cancellation token these two parameters so we can simply omit these how we'll do it we'll say underscore H request message we don't want it then again underscore we don't want this the cancellation token it should return task of string we'll say task do from result from result anything so let's say string. empty like this and now we are good okay so this is all the setup we need just there is one missing piece we are saying that authorization value is string. empty but that is not true we should have this token from somewhere so we need to Define that somewhere and that somewhere is going to be one service which we are going to Define in our services folder so here we are going to create a new class and we'll call it maybe global Service or let's call it common service common service okay public class common service and this is going to have one property of type string or maybe let the label string here we say token and it should be get set or maybe we can make it private set so that we can control who is setting the value to this token here we'll have one method public void set token and we will get a token as a parameter and then we will set this token to this token value cool now this common service we are going to set this this token whenever we are authenticating right so that means from our uh o view model if you go to view model login register view model we are submitting it after that we are moving away to the next page instead of doing this we will do this but before doing this what we can do we can set the token so in order to do that we need to inject common service to our login register view model for that let's add a Constructor here and we will add common service we will inject common service let's create a private readon variable here and then we are going to use this we'll say common service do set token and here we are going to set the token which we will get from our login or register API Cod okay we'll add it actual code but before that let's go because we are injecting it common service we need to register this common service to our dependency container my program and we have this Register App dependency so what we need we need a services. add singl only single instance throughout the app of this common service like this so that we can set the token from anywhere and we can access the same token from anywhere in our app cool now we know that we have the token in common service we just need to get that token when we are setting a rapid settings so here this parameter which is sp which is service provider here we can access our common service where we'll say common service equals SP dot get service or get required service common service now we have access to this common service so here what we'll do we'll say authorization header Val you get this task. from result now we have this common service dot token now we have this and to make it uh safe we can the string. Mt if common service. token was null we will use Simple string. Mt great so everything is fine now now how it is going to work whenever there is any call going from I user API using this St client it will check that on this we need this authorization header to be set so it will set this authorization header but for its value it will go to to this property and then it will execute this thing and then it will get this token from common service so it will have that token great we need this only for this API that's why I'm having it here if this is required from multiple apis you can extract out this logic in a separate function separate method same as I have done for this setv clients you can do this and you can use that for all these but I do not need that for I AP and I API so I'm good with this great so enough talking Rait client is done we are good now let's move back to login register view model again and right now after common service I'm going to inject now how how can we use the API calls from Rapid that is I'm going to show you now so we are going to inject i o API we'll call it Au API like this now on this Au API in here in submit command after setting is BU to true we can say Au API Dot Login async or register async like this right we can directly have these methods and we can use this here so login as sync and register asnc so instead of doing this because we need to now check if this call is for login or for register so let's do one thing let's create a new service we'll say all service because we are going to need other things as well from this Au service I'll tell you what those other things are the first B service and now what we can do instead of injecting this common service and Au API in this view model we can inject these things in our service and then we can remove these from here I'll do this only I'll inject this here let's make private read only fields like this cool now this file this Au service this is going to have couple of methods and properties right so first thing we will have a method public Asing task login Asing then we are going to have a method for register ring or maybe because from there we can use direct sing single thing so let's say login register iing it would be used for both after that we can have one log out method here and then we can have helper method to get the logged in user details so do we have that logged in user model somewhere no we have not it so we will Define it private void we'll say get logged in user let's say get user like this and then we can have uh one property so we'll say public pool uh is logged in so these are the things which we will need in AU service okay we will provide body for this but before that let's go to login l view model remove this Constructor we don't need this now we can remove common servicecore IO API and then we are going to inject Au service in this login register group Au service and then from submitting when we are submitted at that that time we will say all service. login register ring and then we can provide our model from here cool so okay login register async this will get a login register model as a parameter okay and then from here we can pass it login regist model so we'll say model like this and we need to await it and now we can remove this manual delay we don't need that now cool now let's go to login register asnc here we have IO API now we'll provide body for this one so here what we'll do login register is okay first thing we will check if model dot is new user this is the property which we have defined on login register model this is new user so we are using this if this is new user we will go to register API if that's not the case we will go to login AP okay so if this is not this one and return return type of both these calls is same which is API response of au response DT this one okay so we can say API response like this and then we can say here API response dot sorry not DOT equals aore API do registeration now we need to provide register request dto we'll provide this we'll say new register request dto and we can set all three parameters name email and password password we are good with API response mod and we can copy the same thing go to Second else case and here we'll say login with sync and this type is going to be login request DTU what is this login ising login request D yes it should have shown error oh because parent type it should be login request D to you and from here we can remove this name cool now we have this API response you can remove this remove this now on this API response we can check if this response was successful or not what we'll do we'll check if API response. it success then do something and we'll check the negation if API response was not successful that means we had some error okay for that error what we'll say we'll say AIT app. current do main page app do current do main page do display alert and here we'll say error and the message going to be API response do message and the button will be okay so we'll display this alert this error alert and then we'll return from here and if AP response was successful that means this thing worked then what we'll do we will fetch the user information and token information from here okay so first thing we can set the common service. set token and the token I can get from AP response. data. token okay then I can let me access the user details as well so logged in user we don't have that logged in user in uh shared D this is fine enumerations this is fine or maybe in our models okay our models Let's uh create a logged in user model which will be us used in our Maui application only so in models let's create a new class and we'll call it logged in user let's make it record so we'll say public record B and on this we will have ID then name I think that's all what we need ID and name and we will need token as well I'll tell you why we need token so we need these remove everything and now we can use this logged in user here so we'll say new logged in user ID which we can get from API response. data. ID user ID then name API response. dat. name and then token API response.data do token cool now we have this user we have we have set the token now we need to store this user information somewhere and that should be persistent because we when we will close our app and open it again it should have the same piece of information right so for that we are going to set this users information and this information is not encrypted not so this is not that sensitive so we can store it in preferences and if you wish to you can store it in Secure Storage I'm going to store it in preferences only so what I'll do here I will create a helper method private uh void I'll say set user and here I'll use the logged in user as a parameter like this and then I'm going to set this user to the uh preferences here we'll say preferences preferences. default do set and here first we need a key so for key we are using our UI constants so let's add one more key here here we'll say user infut and the value should be can be anything let's use the user Ino only so here we'll say UI constants dot user info comma Now value so this preferences this is a simple storage so we will store string information that that means Json representation of our logged in user model for this what I'm going to do I'm going to go to loged in user and I will add methods here so the methods first I'll add a instance method public string and I'll say to Json like this and here I'm going to say Json serializer do serialize this then I'm I'm going to have one more method static Factory method so logged in user and here we'll say load from Json we'll have string Json here and from here first thing we will check if not string do is null or wh space j if this is not null or whes space if that's the case let's make it null Lael if this is not null or white space we will simply use Json serializer do deserialize logged in user Json and if this is null or empty we'll simply return n or we can return default like this and we are good let's go there now when we are setting it we'll set user do 2J like this because this is single line we can make it expression bodying like this now we are setting users to the storage in preferences so we'll say here set user and this user like this and then we are setting our token so everything is fine now save and great now if this operation this login operation was successful or no we need to notify we need to return something so that our view model our login register view model would know that was this request successful or not for this we can simply return Bo from here if everything was fine it will return return true and if there was some ISS issue it should written false like this great cool now we have this login register logic after this let's go to our log out logic in log out first thing we'll set common service. set token token is token is going to be null because now we don't have token we have logged out so there should not be any to great after this the way we are setting user we are setting it so we need to remove this from our preferences users information so we'll say preferences. default do remove and then key which is this user inut UI constants user save and we are good now this property logged in is logged in for this we can simply check if preferences. default to if this has this user info key if it has this key that means we have other user is logged in okay now comes the get user method it should return logged in user and here first thing we will get the user Jon from our storage that is preferences preferences. default. getet key is going to be UI constants do user info then it requires a default value for default value we can use string. Mt now we'll check if this user is not equals to n what we can do we can simply split return logged in user dot load from this one and this is going to be this user this like this now we have this get user method also there so this file is ready Au service is ready to be used now we will register this Au service in a dependency container so we'll set it as a transient so service is. transient service and we are BR this cool now we are using this s Service in login register view model right we are using it here now we can store the status we can check the status like this when we are logging or registering the user here we'll check if status is true then only we'll redu direct user to the next page if that's not the case we will not do anything because the error if there was any error it was already shown from off service if you go here if there was error we are already displaying it as an alert so we are good with this complete cool there is a lot of code now I'm going to run it and we will see if this login login register thing is working so for this first we need to run our API so I'll say debug and start without debugging it will run on our Dev tunnel the only downside of you see starting Dev tunnel quot this so Dev tunnel is running the only downside is we need to be connected to the internet always and sometimes my inter internet is very bad okay so it is running and we have it here it is running if I go to pads let's see if we are able to fast the data I run it and we have the data that means this thing is working cool now if we run our Maui app it should also work I'm going to run it so go to mobile run it on ulator let's see if we break something or if we miss something or everything is working there is some issue I missed something what is it expected something this okay save Run Okay app came so that means means so good so far this time we land on login page okay we can switch to register switch to login and if we enter something random in login login it came here continue we can see the loading indicator and then we have some error which says response status code does not indicate say 400 bad request we need to uh handle this API validation exception ref but why is this 400 bad request stop it let's add all the PES so from login register Ring We Came Here register request dto in this case it came here right login request D login request D it was the class email and password and on API side if I go to API is there something nothing right login is sync if we go here this is a post request with login request dto why bad request API controller B controller login HTTP post everything looks fine okay let's see if we are getting the data or no so let me add break points in this login register isnc method add something oh May because this is uh this was not email that's why login we are here continue we are here user does not ex okay because that was invalid email that wasn't an email who so error user does not exist okay in this case we'll be on this page only because yeah we know user does not exist right let's switch to register and here we will create a user we'll say test user and we'll set email as let's say test at test.com the password 1 2 3 4 5 6 save register continue continue it is loading and we move to homepage that means user registration is successful okay now let me stop or maybe let's rerun the app this time we will try to login with this credential okay so let's say test at test. 1 2 3 4 5 6 continue continue it's loading and we move to homepage that means login and register both cases are working now for that error that came from here but we were not able to get the actual error so for that what we can do we can wrap this thing the calls in try catch block and in the cat block we will handle API exception which comes from ref like this and here we can handle it so here we can simply show the same similar alert message error and then we will say error in login register or we can add check the condition or we can directly say tx. message and if you want to get the actual error or other details we can simply add a breakpoint here we can check it has one content property as well it has status code reason content headers content property so this content content property this will have more details so let me rerun the app and this time we'll do the same thing we have done in the first attempt so I'm going to add invalid email then let's see and now we have this issue again because this time we are using refit so we will remove it from here and what we'll do for this AP exception we'll say this ref. AP exception what I show with this one local variable sh response okay let's set it to null because we know it will be added the value will be assigned in if and else but it is not able to figure out so we are good let's run it it's coming okay let's do the same thing this login and we came here exception we can see the actual exception message response status code does not indicate success 400 but if we check the complete details we have this content in content we have status is 400 title is one or more validation error occurred errors key value payer key is email value is this and here we can say the email field is not valid email address so if you want you can uh add a logic to deserialize or flatten this error message okay we'll continue and we have this generic message cool object reference not set to an instance of an object and it came from where let's handle this one as well so from here after catch it must have come here and AP response was null or this things it so we should use we should return return false from here cool okay so let's try it one more time with invalid and valid both uh approaches both cases first let me disable all the break points I don't need any breakpoint let's add invalid details login and the error came nothing break now let's add the test ADD test do ABC I'm adding invalid email this time with the correct password 1 2 3 4 5 6 it should say user does not exist correct now if I use the correct email and incorrect password it should say incorrect password and now if I use the correct email and correct password and login this time login was successful and we move to homepage great so everything is working fine we'll stop it and now we'll go to our main page the first page this one why we'll go here because we are moving to login register page page if we have already shown the onboarding but this is not what we want now we need to move to homepage we will not keep on showing the login page or register page again and again so we'll show onboarding page for the first time when user visits our app for the first time it will go to onboarding page and from onboarding page it will go to login page and if the user visits the app again we have already shown the onboarding screen then we are simply going to navigate user to the homepage regardless of whether it is logged in or not doesn't matter we'll move user to homeage because our app allows non logged in user to uh navigate through our app because he can see the details he can uh he cannot adapt adopt the pad and uh add the pad to fabes these two options user would need to we logged in apart from this every other action is okay so let's run it this time it should directly land on homepage if you go on homepage where is it this here great now we'll start working on our home page we have already set up our UI and that connection so everything should work fine now we just need to work on uh the homepage you are designing and patching the data great okay so let's start working on our homepage so first let me clear up everything close all pages all tabs what did I press I don't know okay let's open mobile view models and we'll create create a new view model for our homepage so we'll call it home view model this is going to be public partial class and it will be derived from base view model cool in here we are going to have couple of collections so private I numerable pet list d so let's add this as well to the global usings global usings global using and this goor let's add enumerations as well okay stop okay API is running okay so here we are going to have new added pads or let's call it newly added only and we will have default value of enumerable of empty and pess DTU and this is going to be an observable property and for this let me copy this couple of times so we'll use one for popular pads then we'll use one for uh random BS and all these three are going to be observable property we are going to fetch the data from the API and then we'll add the data to these collections cool and now after this let's add Constructor so in this Constructor we are going to inject our pets AP so I we'll say I pad API we'll say Pats API and like this we are good now let's create that initialize method where we are going to initialize the data initialize all these collections so we'll say public async task initialize a sync a sync like this okay and we are going to have one field here we want it to be initialized only once so private boore is initialized is initialized and inside this method first line we will check if this is initialized is true we return from here we will not do anything cool if that's not the case we will first set initialize to true and then we'll do our logic or maybe we can set it after but for now let let's set it like this only here we will add try cach block okay and in here we are going to call our Pats API to fetch data for all these three and now these three are not dependent on each other so we will make uh parallel kind of calls for this so for this we will not directly await this instead we'll simply trigger this so we'll say newly added task it will be Pats API dot get newly added Pats async the count uh let's get five after that we'll have popular PS task and here we'll get get popular pads Asing and let's patch 10 and then we'll have some random pads the random pets task so we'll say get random pets and let's P six cool now we are going to AIT all these and pass the data so we can do this directly newly added this is the collection this I enumerable observable property so we are setting it we'll say await newly added task and now we have the data from here we can call data which is Pat list D array cool we can use this popular pads second one then random pads third one this is going to be popular and the third one is going to be random like this cool and here we can have exception or API exception which will come from refit refit or repit whatever you call it I call it RIT and then finally this is I'm having because we have that is busy flag so I'll set it to True at the very beginning then in finally block we'll set this is buy to false okay and then is initialized this should be here that everything is initialized this is initialized okay cool so now if it came to catch we can simply say display alert or show alert async show alert async and we can say errors and then message we can set ex. message and button text let's add default button text so that we don't need have to type it again and again if we are using the default version so we'll have okay so like this and we'll say wait and we are good now okay so initialized a sync this is fine this is fine everything looks fine now cool save everything let's register this home view model go to Maui program and here we are going to register it so services. add Singleton because this is the first page so we'll set our view model at single T and we'll add add as homepage at single time homepage like this and now we are good now let's go to homepage we will inject our home view model view model we set binding context of this page so binding context equals this view model view model and then we are going to override a method which is on appearing and we will AIT view model do initialized isnc like this and now we are good with the setup let's go to homepage. ZL and here we are going to add uh couple of name spaces first we'll set xmlns VM which is for view models so view models then we'll add one for our models so we'll say models and then let's add one for xmlns are dtos so dtos DTS cool and then let's set the data type of this page to our home View model like this great so now first thing we'll start the API start without debugging and then we'll run our app navigate to homepage and then we'll start designing our homepage and we have issue here which says URL API pads content has parameter content but no method parameter matches this the reason is this constraint this route constraint this is uh we could say specific to asp.net course routing so in controller actions and in minimal API endpoints it is allowed but for our refit clients so if we go to iPads API so this thing it is considering it as a complete parameter name but that is not correct so here we just need to do this just remove this route constraint this type remove remove like this okay and same thing we'll do in our users API if we have something yes we we have it so remove it and remove it and we should be good now let's run okay app is loading and we are here 404 not found and which one not [Music] found home view mod model newly added popular random we might have missing something API PS new count API PS popular count API PS random [Music] count this is fine right is our API running yes our API is running let's check it from Swagger new count okay this is the issue random popular new this is API pads is missing from these why is it missing let's go to our API controller Pats controller and the reason is we are starting it with Slash so when we start it with Slash it uh removes all the route prefix in this case route prefix the main route we have added at controller level so it should start from API SL controller name which is Pets so first one would work same but if we started with Slash it removes all the route related stuff from the its parent basically so what we need to do we need to remove these slashes let's verify in other controllers all is fine and user controller adopt adoptions favorite fav is right so here we do not have that uh starting slash right so we should be good save everything close the API stop the app we'll run our API again and then we'll start our Maui app so debug start without debugging we'll say response status is 5502 and now we have all these URLs it should work now let's fetch two new pads so we have it cool okay now start our app Maui app it should run without any error now okay cool now let's go to homepage DL and we'll start designing our page so first thing we don't need this tab bar here so we don't need this title and here we'll say shell. nar is visible false cool after this what we are going to do we are going to have a grid the main grid that is because we need uh one section to display our uh that activity indicator okay so activity indicator would be on top of it okay so we'll say here row definitions first one let's say 80 and star so first row is going to be for the uh user name basically so this and in here first we'll have a vertical stack layout with grid. row zero after that we are going to have a scroll view with gr. Row one in this scroll view we are going to have all our complete data and then I'm going to have one activity indicator so let's have some background and then on top of that we'll have activity indicator so for that I'll use grid and in this grid I want this grid to take up the entire screen everything so Rose span two and inside this grid first I'll have a box view with color of our static resource primary color and an opacity of uh let's say 0.8 like this and we can see something great after this I'm going to have activity indicator and vertical option Center horizontal option Center and color white and we cannot see this okay that's because we need to set is running to true and now we can see it okay fine so this should not always be here it should be only if is busy is true so we are going to handle this on this grid level so here we'll say is visible this should be binding is BU so save now it will not be here and if I start the app then it should come initially before the all the API calls are done and once all the AP calls are done it should uh hide so let's see I directly moved there okay let's try where are we where is our home view model and here let's add a task. delay let's say 100 Ms rerun and we can see it fine it was there right so that means this is working cool let's start uh adding other uip pces the first this vertical stack layout we will add our name to this so here we'll say we'll have a label with the text uh we will make it Dynamic well let's make it Dynamic right away so here in our view model let's have one more observable property so we'll say private string his string and we'll say username user name and we'll have a default value let's say stranger and this is going to be an observable property we'll make it Dynamic we'll fetch it the data from our login status okay right now in here we can get this text from our binding username like this and on this we'll have a string format what we'll say we'll say Hi and then username so this usern name like this it should say hi stranger it is not showing it let's add one more uh label and here we'll say hardcoded text let's say welcome okay we can see welcome but we cannot see username the reason might be we added it to the view model but we didn't rerun the app let's rerun and we can see this okay okay now first label let's add some font size so let's make it 16 and on the second one let's say font size 20 save and we can see this edit just keep on editing on this vertical stack layout let's add a padding of let's say 15 okay and the spacing between these labels let's add it five okay okay okay this vertic St layout is fine now let's add the all the collections inside this scroll view we are going to add all these things so in here we are going to have one vertical stack layout okay and now inside this vertical stack layout first for newly edit pets we are going to have a carousal view so here we'll say carousal view with item source as binding newly added okay and now inside this we'll say carel view. item template data template and data type is going to be Pat list D this one for this cool and inside this we are going to have the name price and uh image of the pet so for that we will first have a grid with three rows so row definition we'll say Star Auto and auto and then we'll have some spacing between these rows so row Spacey five like this and inside this first we'll have that rounded image for that we'll have a border where we'll say height request 250 width request 250 and then stroke shape stroke shape we'll say round round rectangle of 125 and then on this one we don't need any border around this so stroke Tech zero inside this we are going to have our image and the source this is going to be from binding and this should be image now we'll have one problem I'll show you what the problem is Source then on this we'll set the same height request 250 and width request 250 and then aspect fill okay we cannot see anything after image or let's say after this border which will be grade. row zero this border we are going to have one label the label grid. Row one and in this text is going to be binding name if we say this we should see something nothing is coming here something is here there was something let me rerun so the collection view caral views these these designs for uh the dynamic content this is not very good developer experience I think hot reload does not work properly that's what I mean we can see this Rani you see Amar we can see this image and we cannot see any other image we can see only this image the reason is all this this URL if you see in our database uh data entities or in pad context we had our seeding data so this initial seat data images if we check image image image image image is img2.jpg img3.jpg so how this is going to work when we set this image to this image view image control it is expecting this image to be inside a net Maui project itself right that's that's what it means that this image is local image but that is not the case in our case right we do not have all those images now this image does show properly the reason is because this is the same image we are using on our onboarding screen so this image this image in fact exists in our resources and images folder this is one of these IM IM 21 or 22 22 this is the 22 so that's why we can see this image and we we cannot see any other image so we need to fix this we need to uh change this image inside this pet list DTU to have the fully qualified URL complete image URL okay what I mean is complete image URL it should be with the complete API URL because all our images are in our API project trip W root images pads so it should be our API URL SL images / pads so for this what we are going to do we'll go to extensions we are in mapper then we are in selector so in selector at this place we need to modify this image so it should be like this first we will have our app constants dot base API URL right/ images SL pads slash then we'll have our this p. image so this is the URL and we should do the same thing for our mapper for this image so let me do this fine stop and then stop the API also because we made change in API we need this thing cool now we'll run our API so debug start without debugging and looks like this is working okay let's check API pad St out execute and now we have the URL complete image URL right if we check this image URL if we go to the new tab add it we should see it is showing 404 and why so URL is final images PS img25 okay okay so by default API does not uh enable this triple W root folder for physical files for static not physical static files so we need to allow this so we'll go to API projects program.cs and here we will say app. use static files so this this middleware will allow content to be served from trip W root folder for static files JavaScript CSS and images so if you do this and now if you run our API debug start without debugging we should be able to see the image we are here let it run okay API is running let's see if this time we'll be able to see the image if I refresh it and I can see the image all right so that means if I run the mobile app now we should see all the images in that carousal view okay and we can see these image right cool so this is working fine now let's design the name and all these so go to homepage. ZL we are here and on this label we'll say vertical options at Center and hot reload is not working again okay never mind we'll add all our design all our styling then we'll sa if I everything is fine on so font size let's make it 20 and then font attributes bold and after this label we will have one more label with grid do row two and this time we'll display the price okay it came after a while it came so but still it is not Center aligned it should be Center aligned but okay vertical opt oh my God I set vertical option it should be horizontal options right H my bad horizontal options Center Center fine and this price one we will uh 20 is fine right or maybe let's make it 18 and on this one we'll say text color we'll use our primary color and then we'll add some formatting to this so this is a price we'll say string format and we'll simply say convert it to currency cool okay it looks fine now let's rerun so that this gets fix so no no no we have some issue here okay we have some issue here so if I go to a border 250 250 and on image 250 250 so everything is fine then what's the issue all these are clipping from the top right let's rerun okay so reun fixed it now we can see all the images name and the price of the pad okay let's increase this spacing a bit this was on our grid we had row spacing five let's make it it Okay Okay cool so this section is done let's collapse it and after this Carousel view we'll work on the next section which is going to be our uh popular pads section so for that we are going to have again a vertical stack layout H this should be the child so here we'll say in vertical stri layout first we'll have one heading so that is going to be label with a text popular pets and then font size 22 and font attributes B okay cool popular pets let's add some spacing between these so we'll add it on the main vertical stack layout inside scroll view so on this vertical stack layout we add a spacing of let's say 10 okay okay now this should be there should be some spacing between left and right so we'll add this on this vertical stack layout uh should we add this on this vertical stack layout or we can add it on top vertical St layout only so let's see if we add it on here adding 15 then what will happen okay it will going to apply it on carousal view as well but we don't need that on that one okay so we'll add it here padding 15 okay fine great after this what we'll do we'll simply uh Define one collection view so same item source is going to be our binding popular okay we can see this we need this as a horizontal collection view we don't need it it as vertical so for this we'll explicitly Define collection view do items layout this is going to be linear items layout and the orientation is going to be horizontal and on this we can set item spacing as well so we'll set 10 for this like this cool and after this we'll add a item template item template data template X data type P list D okay now inside this this data template we will have image and then the name of the pad and image we have the same structure this rounded uh image so we'll say data template and inside here we'll say we'll have an vertical stack layout with spacing off our L spacing two and then we'll have a border with height request of 100 and width request of 100 and then stroke shape is going to be round rectangle 50 and then stroke thickness we'll use zero we don't need any stroke thickness inside this we are going to use our image and source is going to be binding image and then height request same 100 and width request 100 and uh aspect fill so now we should see this cool we can see our collection view with this popular pets fine so on this vertical stack layout let's add some spacing so in popular pet and these pads we should have some spacing between these two so we'll see spacing let's say 10 10 is fine not much or maybe let's make it 15 okay okay after image after this border let's have a label for the name of the pet so here we'll say text binding label text equals binding name we have a name and why is it repeating I don't know why is it repeating maybe this is also some uh issue related to hot reload two times five times four times okay let's add after this text binding name we'll say horizontal options at Center okay and then we'll have a front size of 16 and let's have the textt color as a primary color static resource primary okay so let me save it and rerun okay app is here and now we can see it it is same single item only so the name is single time only so this is fine cool now we'll work on the next section which is going to be our that random P section so for that what we'll do we need to copy this complete vertical St layout and then we need to change this text and then on this collection view we just need to change the binding Source item Source instead of popular we'll use random so what we can do we can maybe uh move it to some separate control uh let's do this this item template this data template let's extract out this data template and we'll make it as a static resource and then we'll reuse it for both of these sections this popular pads and the random pads okay so what we'll do I have just copied this and we'll go to the very top and here we'll say content page. resources here we'll set a resource dictionary and we'll paste it here data template is here and then we need to set a key here and we'll say uh PS horizontal list something like this horizontal list template save everything and now we can directly use this so we'll go here and we'll remove this item template completely and on this collection view after item Source we'll say item template and here we'll say static resource this one so we should have the same visual great now it is smaller clean now let's copy this vertical stack layout paste it one more time and this time we'll say instead of popular pets we'll say you may like for random pets so we are just throwing some random pads here and the collection is going to be random save everything and boom we have this section we have this section and we have this main top section okay we can have right now we do not have that uh indicator view so we can have that indicator view as well or maybe let's not add it or add it I don't know I'm not going to add it if you want you can add it okay all right so now we'll work on before working on these all pads favor profile page let's work on the detail page pet detail page whenever we tap on any pet on this home screen from this main caral view or these collection views it should open a new page The Details page okay so we'll work on that page now so for that we have already created a page that is this Details page for this page first we will need a view model so let's go to view models create a new class and we we'll say details view model okay and this is going to be public partial Class View model and the base class is going to be base view model cool now inside this we will have the pad details that means we are going to have that pad details DTU that object we'll change that later but for now we can work with that and that is going to be an observable property so we'll say private pet details Vore pad details okay and we'll have default value as new here we'll say observable property and this is going to be filled okay from the previous page so previous page is going to pass pet ID to this page and on this page we will fetch the data on the basis of that Pat ID okay so that means we need to have one more observable property so we'll say private [Music] intore pth ID and this will be observable property and we are going to use this pet ID as query property as well query proper name of Pat ID and name of Pat ID like this now we are good we will save it and now whenever this pet ID is being changed so we'll use the similar approach we implemented on our login register view model so here we'll use a partial method on pad ID changing or change let's use changing only okay and we should we have it as async partial void can we have it ASN yes we can okay so in here whenever this pet ID's value is changing so we'll say patch the pad details from the API okay so we'll fatch it what is the issue this is n list edit so that means we need to have our Constructor ready so we'll say Constructor and we'll inject our i pads API pads API will create a field private read only field Pats API okay and now we can patch that but before patching that what we'll say we'll set ISB to true then we'll add a TR catch block TR catch finally and in finally we'll set is B to false okay okay and now in here we'll say exception ex and here inside this cetch block we'll say a wait and show alert a sync like this and we'll say errors as title or we can say error in fetching pet details and then we can have the complete error message like this okay now inside this PR block we need to fetch the pet details so here we'll say word pad equals a wait uh pads API Dot get Pat details async and we need to pass the pat ID but this Pat ID does not have value yet so we will use this value can we change this name yes okay so let's remove this now we have this pad ID what is the issue partial declaration have diff signature different int value in P ID uh I have not tried it if it works with partial if we change the name of parameter let's see if it works if it not then we'll use that value only P ID pet ID we are good everything is fine it should work okay let's add a break point here and let's try to run it and how would we reach this we won't reach this right so stop it stop and and clear details view model let's use this on our uh Pages first let's go to homepage not not homepage we go to Details page here we'll inject this details view model view model view model like this then we'll set our binding context on this this view model OKAY save everything stop we need to rerun the API okay we'll run and from homepage whenever we tap on any uh pad it should go to the pad Details page that means we need to have one command in our home view model so here we'll have one command which will say private async task will say go to the tail spage and we'll get P ID as a parameter here and from here we'll say go to a sync and then we can have our URL that is going to be name of Details page and after this we can have this squarey parameter directly here we'll say name of details view model pet ID equals this pet ID like this and because this is single line we can have it like this we add a weight and we have this ready we just need to decorate it with relay command Okay cool so this command is ready now we need to use this command on our home page do ZL so let's use it so how we are going to use it on our Carousel inside our grid in data template in our grid we can use grade do gesture recognizer T gesture recognizer and here we are going to have a command this command is going to be binding source is going to be relative source source ancestor type is going to be X type and this will be our home View model like this and on this the path is going to be the go to Details page command what was the name home view model go to Details page command command F and after that we will set our Command parameter which is going to be binding this p. ID so we can have ID directly like this it should work and now we need the same thing so I'll copy tab gesture recognizer for the this section vertical stack layout for popular and random pads so we can go to our data template in our static resource resource dictionary and we'll add it on this vertical stack layout so on this let's say vertical stack layout do gesture recognizer and I'll paste it like this save everything and now it should work it should open that page but before that we need to add that page to route for that we can go to appell or we can use Community toolkit Maui's method in Maui program here we'll say services. add transient with shell route we'll use this one first should be View and view is Details page then we should have view model which is details view model and then we need to have route which is going to be name of detail page so now it has registered it as transient and generated a route for us which we can directly navigate to cool so I think [Music] every thing is bind up now just one thing on Details page we don't need this title we can say shell. nar is visible to false add name spaces so we can copy all the name spaces from our homepage like this name spaces and then we'll add the date save the data type of this page this Details page is going to be a details view model this thing so save everything and let's run and then we'll start designing our app first let's start the API start without debugging okay now we'll start our Maui app and we have some error and the error is we missed semicolon here okay the app is here if we tap on it on pet ID changing we'll go here and and we move to this page and we should see the pad details we have data it success message and we have this complete data cool so we are good I think let's use this pet and this should be API response so we'll say if API response Dot it success then set pad detail this pad detail equals this API response do data if that's not the case we have some error so we'll display that error in here we'll say uh API response do message Api response. message fine so now we can remove this breakpoint and we can directly use this pad detail object on our uh the detail page let's run it okay it is coming and unable to resolve this and my internet disconnected okay let me connect to the internet and rerun the app okay so app is now ready and if you tap on this it moved to this detail page if we go back buddy and we are on this page so that means this thing is working and we can start designing the detail page so first thing we'll do we will change the presentation mode of this page so we don't want this page to be directly uh open it as a page so we have shell. presentation mode and here we are going to say model animated so if we go back and come to this again we need to restart the app it's loading okay app is here now you see it came from the bottom like this cool so for this model animated model presentation mode the problem is it does not show that uh Navar and that back button we need to work on that manually but that's fine we were going to design this complete page for ourself only okay so first thing let's set the background of this page so we'll say background color static resource BG color okay after that in this we'll remove this vertical stack layout and we are going to have a grid here and on this grid we will have rows row definitions first we'll have Auto whatever space it can take after that star and star and then again Auto so first one is for header second one is for image third roof is other details and the last Auto is for button that adop button okay and then on this one let's add some row spacing let's say 20 and now we can start working on the main design did we set data type yes details view model is our data type so in this first we'll have a flax layout grade. row0 and in this Flex layout what we'll have we are going to have an image so we'll have border with the background color of white white then height and width as 30 so height request 30 width request 30 and then stroke shape we'll use uh round rectangle round rectangle of five and we don't want any stroke thickness so we'll say stroke thickness zero and we are good let's add some padding for Tool and inside this we are going to have an image and Source this will have left Arrow this icon is already added so now we can see this nice icon here okay on this grid let's have some padding we'll say padding let's say 10 from left and 20 from top and 10 from other two sides so 10 from all sides 20 from the top okay now inside this Flex after this border we are going to have one label to display the page text which is going to be pad details P details like this okay and now after this we will again going to have some image the similar thing we have in here so let me copy this paste it again and this left Arrow I'm not going to use this left Arrow I'm going to use this heart icon this one cool so save everything now we need these uh the icons on the very left and right and the pad details should be in the center so on this Flex layout what we are going to set we can set justify content which should be space between like this cool and okay so this label let's increase the font size of this label so we'll say let's say 20 and we'll use Font attributes bold vertical options Center so all these three things will be in the same uh what do we say same alignment and let's do the same thing on Border as well the vertical options Center so vertical option Center on this one and the last one as well so now both of these borders have the same uh this designing same styling so we could extract this out and I think we are going to have the same thing somewhere else else also we'll see it later so right now we'll say content page do resources resource dictionary and here we are going to create in style target type border and we'll add a key here so we'll say icon BTN container something like this and here we'll set setter seter property and then value like this and let's see what all things we want to set we want to set everything so let's add it here so first padding value four and let me duplicate it then we'll say background color as white then comes height request background color white height request 30 width request 30 after that we have stroke shape which is round rectangle 5 then we have stroke thickness which is zero and then we have vertical options which is Center like this and we are good we can use this icon BN container Style on these borders for the first border we'll say style static resource icon B container like this and let me copy this and add it to the second border as well so now it looks clean cool we have the header ready now let's work on the second part the second part is going to be the image so here we'll say border grid. Row 1 this is going to be the first row and here we'll say height request 300 width request 300 stroke shape round rectangle 150 and then we'll say stroke thickness zero and horizontal options at Center and let's set vertical option Center as well but it does not matter in this case so maybe we can remove this as well okay now inside this we will have an image source this will come from binding and it will be Pat detail do image like this and let's set the height and width same as its containers height request 300 withd request 300 and then uh aect fill okay cool after border let's start working on the next section which is going to be our uh the details of that pad so for this we are going to use uh [Music] grid okay so grid do row two and here we will have three row and three columns three row and three columns so here we'll say row definitions Auto auto and auto and then column definitions we'll have star star and star so columns three equally uh spaced columns okay and now in this grid so first we'll have a label gr. row zero and grade do column 0 and then in the text we want to display pet name here so Pat details. name like this and we can see this cool let's add some styling to this so font size 25 F attributes bold okay now it the name could be long we we have three columns right so the last column we want to display the not we want to display the the price so for this let's have a border grade. row0 grade do column 2 so on the first one let's use column span of two so the first two columns would be uh for name and the last column is going to be used for the price for this border so grid. row0 grid. column 2 and then for this we are going to have a background color of white okay stroke thickness we don't need any SL lickness and we will not Define any shape so it will be default shaped which is rectangle okay okay now inside this we are going to have a label for text uh finding then pad details do price and here we'll use string format and we'll format this to currency format that is here now let's add some styling so first uh we'll say text color static resource primary color then we'll say font size 25 okay then we'll say font attributes bold horizontal options and okay okay on the this border let's have some padding of maybe four or five okay now let's move both of these two vertically and so we'll say on this label vertical options say end and on this border vertical options as end save everything and we are good cool we have this now after setting the name and price now we'll display the description so for this we'll use label this is going to be grid. Row one and it should take all the column space all three columns so we'll say call span 3 and then we are going to display a text descript destion so it should be binding pad details do description so it is here okay now let's add some styling to this first we'll say font size 16 and then we'll have some line height line height let's say 1.5 okay now let's have some spacing between these so this we can add on our grid level here we'll say row spacing something like 25 Okay cool so now this is done save everything after this now we want to display the the features that breed and gender and age so we want to display that thing so for that inside this grid only for the first grid we are going to have a grid with first thing it should go to grid. row2 and grade do column zero and for this row this grid we'll set row definitions so there will be two rows Auto and auto and two columns column definitions Auto and auto like this and now inside this grid first we'll display our uh that border so we'll say border grid Dot row zero and gr dot column zero H okay first row and First Column inside this grid and on this border other things can be the same as this icon BTN container we can use that style directly here so Style static resource icon B in container inside this we are going to have an image with source so the image for our breed so here we are going to display breed so we'll say breed if we do this we should see this image here and this is here cool we have this breed here after this we'll have one label text and this text is going to be the heading kind of for this particular section it should be grid. row0 and grid do column one text I already set here I'll say font attributes bold and font size 16 so let's see how it looks it looks nice okay now on this top grid let's add some column spacing so we'll say column spacing four okay now after this breed we want to display the value of this breed so which is going to be again a label grade. row no no no we need to show the yeah the value of the braid so we'll say grid. Row one and grid. column one and here we'll say text next binding pad details do bread like this and on this one we'll set font size as 12 and then we need to use line break mode to word WP the reason is we are going to use three uh section on this screen so this name if the name is long it is going to overlap or maybe I can show you this screen so save everything and now we need to repeat this inner grid for two more times for uh age and gender okay so what we can do stop it and we'll create a reusable control and then we are going to use that control here so we have this uh controls folder here we are going to create a control so it should be new item and then net Maui M content view with zaml so here we'll say pad feature control or maybe pad feed control the this thing okay so pad feed control now we can come here and all these three things the icon and the label text and label value all these three are going to be bindable properties we are going to get these as bindable properties so let's create properties here first we'll have one property for Icon then we'll have one property for uh let's say label and then we'll have third property for value and we need to create these as bindable property so let's create those so here I'll say public static readon bindable property icon property equals bindable property do create create and here property name so this is going to be name of Icon this property we defined here then the second return type so this is going to be type of string then third is declaring type so the declaring type is this type only which is pad feed control then comes that's all what we need right or we can have default value if you want default value we'll say string. MTS default value cool so let me copy this for two more times so we'll say icon property then we'll have lab property everything will be same just this label will be changed then we have value property and this should be value and we have issue because of this casing yeah now we have value so we have these three bindable properties defined then we have this these properties so let's use these bindable property in this get and set okay like this this and this then for this getter we are going to use get value icon property and this is going to be typ cast it to string and then for Setter we'll say set value and icon property and value like this cool let's copy this and add for both the label and the value and we just need to change for label this should be label property and for Value it should be value property value property value property save everything add it and we are good now we can use these bindable properties on this uh zaml side so in this zaml side what we are going to do let's remove this vertical St layout we don't need this so the design for this one is already ready on our Details page so we have this grid we are going to use this grid let's commit uh comment it here and here we are directly going to add it save now we need to get these values dynamically icon BTN container static resource so for this thing what we can do let's cut this from here and move it to the main style because now it is being used by multiple pages and uh controls so it makes sense to move it to our uh resources resources Styles and style. ZL move to the very end and here we'll add it save everything let's stop the API it is breaking save cool now we can remove the static resource directly from here and now we can use it here now just we just need to get these values dynamically so what we'll do we'll add a name to this content view let's say this and then we are going to set binding context on this grid it is going to be binding context equals x reference this like this and we are good now now in this we don't need this grid do row two and grid do column zero because these are not related to this section now but apart from this we'll have everything just this breed now we are going to get it from binding so binding icon then this breed which La was uh label so here we'll say binding label and then for this one we'll say binding value and now we can use this control on our this page on our Details page so in order to use it first let's create a name space xmlns and let's say controls controls and then we can use it directly here so instead of this grid we'll say controls pad feed control like this and first we need to provide these two value grid. row and grid do column after this we'll provide the properties which we have defined so first icon which is breed then label which is breed and then comes value which will be binding pad details do value or pad details. breed if we save everything and run the app now but before that we need to run API so we are running our API [Music] first okay looks like API is running now let's run the Maui app okay app is running now let's go to the detail page and we can see the details here and we can see this section now we are going to just copy this control and paste it two more times we'll just change column 0o column 1 and then column two and now we have this section ready cool now we can remove this commented grid we are not using it we'll change this so after this breed the second thing is going to be the gender so this image this is going to be dynamic if you remember we have pad details dot gendered image this Dynamic Property which gives us male or female on the basis of gender then it should the label should be gender and the value should be gender display like this this is female then for the third one we need age so for age I don't remember what is the uh icon is it calendar yes okay label is going to be age and the value is going to be pet do Age 3 years cool great to save everything it is working if you go back this button is not working we have not added it let's check some other things Rani we have the details go back some Luna we have this things ready Lucy okay so this thing is working so this section this name the bottom name this will actually uh look bad when the name is longer I right now I cannot see any breed name which is long longer I don't know this one cat person this is [Music] not Whispers okay right now I cannot say find anything but I have checked it if the name is long it uh flows through to the second column this gender female and that looks very bad so for that what what I have done for this first section uh where is it this value so I have added line break mode to word rep but the problem with this one is it need to know the exact boundaries if I am in a grid column then it does not know the boundary so we need to set maximum width so maximum width request and we can set it 100 so it should look same in this but for the longer one it will break to the next line so it would look good there as well save everything and we are good with this as well great it is coming out pretty good right pause the video and do let me know in the comment if you are following along till this time or you're just watching the video and then you are going to try it later do let me know in the comment okay now let's add that button adopt Now button so inside this grid only let's minimize this grid collap this grid and then we'll add our button so the text is going to be adop now the default text and then style is going to be static resource and our BTN primary if we do this we should see this and we have this add up now button we just need to move it to the actual place so grid. row it should be two two or three three yes grid. Row three cool this looks fine okay so should we have [Music] some margin from the bottom or it should be fine it should be fine it's fine okay so now if you go back open Raja and we can see the details uh we should show that activity indicator right so for that we have this main grid here we are going to have our activity indicator we'll say grid. rpan 4 let's take everything and then we'll say horizontal option Center and vertical option option Center and then the color we'll use our primary color primary and then for is running we'll use binding is busy like this save everything and let's open some pet and for this as well well we need to have it this is busy to true and after that is B is true let's see let's add a task. delay 100 let's see if we can see the activity indicator we have M change here we need to prun on this page is there something else which we are missing looks like no everything is fine on this page everything is fine we can see this and fine okay okay Golden Retriever it is on the second line so this is fine cool so this thing is working this spacing is Let's uh reduce this spacing column spacing for and the row spacing oh maybe because on the first uh that icon grid do column 0 row0 it should be Rose span the icon should be Rose span 2 grd do rose span to okay and then and it should be horizontal option sorry not horizontal vertical option should be top that means start vertical option start okay and then the row spacing should be some let's use four only okay it looks good now okay save everything and we are good let's add some interactivity now so for this heart icon adding it to fav is it would require login and then adopt now also is going to require login so we will work on these two sections later but for now we can work on this back button so whenever we tap on this back button it should go to the previous page so for this what we are going to do let's go to details view model and here we are going to create a method so private as sync task and here we'll say go back okay and we don't need any parameter in this and go to async we can use from the base view model and we can use dot dot so when we are using shell dot dot means the previous page so we'll say a wait and go to a sync dot dot and this is going to be in relay command like this and now we can directly use this on our page our Details page Details page we have this back button so on this we'll say border dot uh gesture recognizer tab gesture recognizer and on this we are going to use a command which will directly come from binding and this is going to be go to go back command like this like this so we need to re the app because we made change in view model it is not picking up that app is loading if you open Bud we have it if you go back and it works yeah it works fine great so that means Details page is also working the thing this adding this icon to fabes and then this adopt Now button this will work later in this video for now let's move to the next screen and that is going to be this all pads screen all right so for this first let's stop the app and first we'll go to our view models and we'll create a new view model for this so class all pads view model public partial class all P view model and this is going to be derived from base view model and in here first let's have a Constructor and we need iads API for this Pats API sorry and now in this first thing we will have one collection for all our pets so we'll say private numerable of pet list D and underscore pets and we'll have a default value a numerable of empty pad list too like this and this is going to be an observable property like this cool now on this page we are going to to implement pull to refresh functionality as well so for that we are going to uh have one field here so private bull we'll say is refreshing and this is going to be an observable property cool and now in this page this is going to be uh initialized only once so for this we are going to have one field is initialized initialized and this is not going to be observable property because we are not going to use it on the UI we'll use to this totally inside this uh this view model only so we don't need to make it observable cool now after this we can Implement our initialized method so we'll say public async task initialize a sync like this and in this H so first we will check if is initialized is already true we'll return from here if that is not true then we'll add our logic and because we are using is refreshing pull to refresh this logic should go to load all pads uh and helper method I think we'll say private isync task will say load all pads like this okay and inside here we can call it from here from our initialize sync so here we'll say a wait load all [Music] pads okay and inside this load all pads first thing we'll set is busy to true then we are going to have our try finally try catch finally here we'll say is busy to false and on this we'll say await and show alert async error in loading pads and then we can say ex. message here like this and now inside this try what we can do we can say API response equals a Vore pads api. get all pads cool now if we have the data so API response. it success then we'll display the data and that is going to be we'll say pets equals API response do data if that's not the case we got some error then we are going to display this error message the message is going to be API response do message like this and this is fine so loading this is fine from initialize when we are coming for the first time we have this ready okay here we should start it is initialized to True like this we are calling it from here then for pull to refresh we need to have one command for that we'll say private Asing task and let's say load pads and from here we'll call the same method we'll say load all pads and this is going to be a relay command relay command now there is one uh ux related issue the issue is when we say pull to refresh it comes with its own activity indicator and here if we are using this is busy then we'll display the main activity indicator which will be on the the page label what I mean is we need to have two different set of uh loading indicators one will be shown by us using this isbg on the page level and then there will be another one which will be handled by a pull to refresh functionality but the variables which will uh these properties which will handle those those are defined by us so one is is refreshing then other one is this is busy so when we are loading the pad for the first time using initialize method at that time it should use is busy and after that if we are loading the PS using pull to refresh functionality then it should use is refreshing so the point is we should not set this is busy to True directly in load all pads because this is the method which is being called from initialize and from this command from both the places okay so instead what we'll do we need to have some State here uh not state of parameter so we could say if this is the initial I load so we'll say initial load if this is initial load here we'll check if this is initial load we'll set is BG to true if that's not the case if that's not the case we will set is refreshing to two Okay and in finally we can uh either have the same condition to set these fals or we can say let's set both of these two fals like this cool now we just need to pass this initial load so from initializing it should be true and from this command it should be false like this so looks like everything is fine now okay let's clean this save everything all Pats view model we can use it in our page before that let's register it so we are going to register it services. add Singleton we are going to set register it at Singleton and then we'll register the page as well so we can create the page as transient maybe add transient all pads page so save everything now we can inject this all pads view model to our all pads page so let's go there all pads page all pads page let's inject it view model and let's create a property uh private only field then we'll set binding context of this page to this view model and then we'll override on appearing and here we'll say a wait view model do initializing cool this is fine now let's go to the ZL and here first We'll add all our name spaces so let's add all name spaces and then let's add say the data type of this page is going to be all pads view model and save everything and let's run the app now we'll start designing our page this page the all pads page it is running is API still running no API is not running so we should stop it we should stop it run the API so debug start without debugging and then we'll run our Maui application okay app is here we can go to the detail page detail page is working and now we'll work on this all pads page so first thing I want to change the title so it should be all pads cool save everything okay now inside this what I'm going to do first I'll have a grid grid without any row or column so first we'll have all our content and that content I'm going to wrap everything in refresh view so that we can use uh pull to refresh functionality inside this refresh view I'm again going to have a grid this time we'll have two rows first is Auto and second is star and this grid I'm going to use to let the user know that this page has pull to refresh functionality so we'll explicitly tell user that you can use this functionality so for that I'm going to have a label here with grid. row zero and here I'm going to have a text which will say pull to refresh like like this and we'll make it very small and uh some grade out text so that the focus is not on this label but it is just an indication that you can do this as well okay so for this we'll say font size 12 let's see if it is there just pull to refresh we can see this so front size 12 horizontal option Center okay then let's have some padding of five cool and we are fine with this just set text color to static resource gray 500 okay okay good so after this label now we can add our complete collection so I'm going to wrap it inside scroll View we'll say grade. Row one on this scroll View and then I'm going to have a padding of five and inside this I'm going to have my collection view so I'll have collection view item Source what is the isue collection view yeah item Source it will come from binding pads like this like this so now we can see all these items these are all pads p to refresh is working but now it is not working we can see this so we'll modify appearance of this refresh view so we can set refresh color so we'll say static resource primary color and now we can see this color great now we need to bind it is refreshing to our uh property which is is refreshing right now it will work is refreshing then we'll set uh brief fres command that we have command directly on this command we'll say binding and load pads command like this save everything okay after this before working on this uh collection view let's add that activity indicator the main activity indicator for the initial uh uh load so here we'll have our activity indicator and for this we'll say horizontal options at Center vertical options at Center and then we'll say color is going to be our static resource primary color and then for this we are going to bind is running with that ISB property fine let's rerun the app so that these two things will work and go to all pads view model when we are loading the pads after setting this let's do that that small delay so that we can see if the activity indicator is there so rerun the app now for the first time when we are loading that screen when we tap on all pet page at that time the center activity indicator should be shown and when the all pads are loaded then if we use the pull to refresh then only the pull to refresh uh that activity indicator should be shown so if we go to all pads we can see it in the section uh in the center then it is gone now we use this now at this time this is the only one and we don't see that both of these things are working now we just need to uh work on the appearance of these items okay so let's work on the data template for this so we have collection view inside collection view we'll come here and here we'll say collection view Dot item template data template and the data type is going to be pad list D cool now inside this first we'll have a vertical stack layout inside this vertical St layout we are going to have a border with background color as white and then stroke we are going to be have it round round rectangle and I'm I'm going to modify it after some time then let's have stroke thickness as zero and we are let's have stroke color so stroke thickness stroke color it should be stroke shape okay stroke shape out rectangle fine inside this border first I'm going to have an image so the image image image should we have image inside this border or we should have a grid with two columns one for image and one for all other things right here we are going to have a grid with column definitions as Auto and star then we'll have some column spacing of let's say 10 and inside this we will have image grade do column 0o and then source is going to be binding image if we do just this we should see the images and we can see the images but these are very big images we need to add some height and width to these images so we'll say height height request uh 125 and width request same 125 okay let's wait it is coming slowly fine okay now some image is smaller and some is bigger so on this image we'll set aspect to let's say aspect F okay okay now on this main vertical stack layout let's add some margin we'll say margin and on this let's have five from left and right 10 from top and bottom cool so after this image we will have a name breed and price of these pads for that we are going to have a vertical stack layout again this time grid. column 1 okay and inside this H inside this we are going to have uh first a label with the text binding name name of the pet we should see this quickly yes then we'll have one more label with the text binding breed and it should come yes after that we'll have a label for price so we'll say label text binding price with string format string format as currency like this and fine we have this now cool so on this vertical option layout we'll set vertical options to Center enterol we add some styling to this name breed and uh this price so full name let's have a font size of let's say 22 and font attributes as bold okay and then let's change the text color to our primary color so static resource primary cool let's add some spacing between these items so on this vertical stack layout We'll add spacing of 10 okay okay let's have some padding as well so on this vertical stack layout we'll have some padding or we can skip this so this is is the spacing is handling this okay now this breed so for this one we'll set font size 16 and then text color we'll use uh light color so we'll use gray 600 should become lighter and okay now this price so for Price we'll use font size 18 the bigger font and then color so text color we'll use same static resource primary color and let's make it bold as well so font attributes bold and it crashed okay so let me save everything and rerun app is running let's go to all pads page we can see this and we can see the items we can scroll around and if we do pull to refresh it should look load the bats again okay so now let's add couple of other things as well after this border for this border we were going to have some line here the HR kind of thing so for this what I'm going to do in this vertical St layout after border I'm going to have a box view with color of static resource R primary color and then I'm going to set height of this to one cool now I want it to uh blend with this image so what I mean is I just I will just add a margin with left zero right minus sorry top minus one right zero and bottom zero like this cool now if you see this border this uh is coming out on the left bottom section this section so for this what we'll do on this border where we have this stroke shape round rectangle what we'll do we'll set 15 which is top left corner and all other will set to zero so it looks like this now what we'll do we'll on this box view we'll set opacity of let say 0.2 or three okay okay it looks cool now after this what I'm going to do on this image I'm going to add some Shadow so for this I am at this image here I'll say image do Shadow and in here we'll use Shadow the color of Shadow I want is our main primary color so we'll say static resource primary like this and after that we will use some radius of 50 so we can see this light uh Shadow here save everything and we are good cool there should be some spacing between these two as well these thing as well the description and this image so for this we'll go to the main top level uh vertical stack layout and the vertical St layout or this grid on this grid we had column spacing 10 let's make it 15 okay this looks like nice cool this is fine we can list down all these pads now when we tap anywhere on this row on this pack it should open the same detail page which we were opening from our homepage so what we are going to do for that thing let's go to the homepage view model home view model so let's do this just go to detail page this thing let's cut it from here and let's move it to base view model because this is the thing which will be used on almost all the screens so let's cut it from here go to base view model and let's add it here cool now we can directly use this thing go to Details page command save save and now inside this uh data template vertical stack layout on this vertical stack layout let's add that so here we'll say vertical stack layout doj recognizer tab jure recognizer command this is going to be binding and we'll get uh X relative source and here we are going to use uh ancestor type with X type is going to be all pads view model and then the path is going to be the go to Details page command command like this and then we'll have command parameters as binding ID this is the pat ID so we are good let's rerun the app it should uh show the detail page from All Pets page now what is loading we are here from homepage this is working same as it was working before right now let's go to All Pets is loading now if we add if we tap on any of this nothing is happening and why nothing is happening is something missing so binding Source X relative Source incest type all pads view model two and then path go to Details page command this is fine right let's check if we are missing something go to home page where is our homepage uh homepage here also we had this tab gesture recognizer right so let me copy this thing go here save it add it I just want to compare both of these have just binding Source Rel Source homepage view model all PS view model path go to details space command right so everything is same go go to Details page command Details page command these are same why the alignment is not same something is not right home view model then okay I was missing this a okay it should work now save everything open it and now we can open it from Details page as well and back go back is also working great so we are good with our all pads page that's all what we had to do on this all P page now we'll start working on some next page okay so now we'll work on profile page so before favorities page we'll work on profile because favorities requires a uh logged in user so we'll work on this screen after this profile page so for profile page let's create a view model first or maybe before that let's close all tabs cool now we'll go to our view models create a new class profile view model okay and this is going to be public partial class profile file view model and then the base class would be base view model save everything and we are good in this let's add a Constructor we would need our uh Au service because we will handle login or log out from this screen so all service after this we want to display logged in user name so we'll have private string underscore username and this is going to be observable property and let's have the default name as maybe not logged in and then here we'll have one Boolean property which will be is loged in and this is also going to be an observable property cool after this if you remember when I showed you demo there was that initials of the user in that uh circular box so for this we are going to have a property here we'll say public string and let's say initials and this is going to be a g only property and inside this we will uh use our username to get the initials so first we need to uh split the username so we'll say our parts equals username dot split and we'll split by space and then we'll add string split options string split options. remove empty entries and we'll say string split options dot trim entries now we have uh splitted this username now we'll check if this parts. length is equals 1 that means the username was a single word so if it was single word then we'll patch the first two uh characters of the name here we'll say return and let's check if although this is not the valid case but maybe for testing purpose we just added a single character to the name we do not have that validation ideally we should have that validation but if we we do not have that validation then we'll handle that case also so that will fall in here username do length if this is let's say equals 1 if username is Single Character word then what we'll do we'll say username and zero that is actual username so we can directly return this then if that's not the case that means username is not a single character it is a complete word with multiple characters so here what we'll do we'll say username dot we can get substring or we can use the range operator so we'll say from the start take the two characters like this and we are good with this first case then comes the second case where we know our username has multiple words in it in that case we will get the words uh the characters from first and second world here we'll say it return parts of zero that means the first word and then we'll get the first character so first is for first word and the second index is for first character of that first word after that we'll concatenate it with parts of 1 and zero so from first word sorry from second word take the first character so this thing now the problem is it will return into two string into string what do you mean into two string okay because this is character okay so we can do this parts of 0 0 and then parts of one Z like this or we could have added two string to both of these cool so now this is going to work we have this ready what is the issue here name is save cool so let me add some uh helper commands here so if the username has only one word that is let's say this is okay and here we are saying this cases when or let's say if username has one word with one character only okay so this is going to be for example let's say I have just a and then comes this one which says username has is one word with multiple characters so in this case the main case a like this and then second is username has multiple words so for example like this cool so we have initials now this is not an observable property because this is a computed property it depends on username so whenever this username is changing we should notify that initials should also change so for this changing of username we are handling it using this underscore username observable property so on this we will add one more attribute which will be notify property changed for name of initials so what it is going to do whenever the value of this underscore username this username observable property is changing at that time it will notify that that with this username this initials value has also been changed so please pull up the latest value for initials as well and then our system is going to pull the latest value for initial so when it will come here it will execute this get part and here we are doing all our logic related to this username so the initials will have the latest username initials okay and apart from this what else we need on this page we'll see what we need apart from this let's first try to use this so on profile page. zl. CS let's inject this view model view model and here we are going to say binding context equals to this view model and then we need to register register our profile view model and profile page so we'll go to Maui program and here here we'll say services. add transient profile view model and then add transient profile page cool now we are good to use our profile view model on our profile page so first let's add all the these name spaces cool and after that let's add the data type for this page which is going to be profile view model fine now let's run our app then we'll start designing this page so first let me run the API sorry okay P running now let's run the app okay app is loading deserialize the response and there is some issue and yes this is the thing which I was saying that the problem is if you go to our API and if we check we do not have our Dev tunnel selected because I Clos this visual studio and I'm recording this section in the next day so till previous section I recorded yesterday then I closed everything so whenever we close visual studio and open it again this Dev tunnel automatically gets deselected so we just need to select it again again so for this we need to set API project at startup project then go here here we'll check Dev tunnels and we'll select our D which is this P option API YT we'll select it and then we are good now if we start it with or without debugging it will uh start the dab tunnel and now if we run our a our mobile app for this when the network is not there we should have some correct error message we should work on that also okay cool it came so everything should work fine as it was working before cool all pads okay from here also we can open the details let's go to profile page now we'll work on this page the design of this page okay so first thing let's change the title to just profile then let's remove this vertical stack layout and here we'll have one grid with the row definitions as Auto star and auto so first one is for the user initials that box Avatar view then second one is going to take all the space which is remaining on the screen then third one is going to be for a login or logout button if user is logged in we'll show log out button here and if user is logged out then we'll say we'll show login button here cool in this let's have some row spacing of let's say 15 cool now inside this first we'll have uh that box rounded box for user initials and then username for this we are going to have a vertical stack layout grid. row0 and in here we are going to have a border in this border we'll have a background color background color of our static resource primary okay then we'll have height and width of 100 height width 100 and then we are going to have stroke shape at as round rectangle round rectangle of 50 okay we can see this this is looking great now next thing we will remove stroke thickness so we'll set it to zero okay and now inside this we will have a label where we'll set text this will come from binding and this is going to be initial okay it is not coming because let's set the text color to white text color white it should come what is the issue [Music] initials uh let's set label text binding username we can see this username then why can't we see initials let's try it here initials we can see it username inside this border we have text color white initials font size 50 okay it might have at the left top section okay okay now let's say vertical options at Center and horizontal options at Center and if user has entered uh username in small case lower case then for that purpose we can use text transform property to uppercase so we want this initials to be in upper case always okay after that font attributes bold cool it looks great then this username we will move it to the center so we'll say horizontal options at Center then we'll add font size to somewhat 20 font attributes bold and then text color static resource primary cool now we need some spacing between these two so on this vertical stack layout We'll add a spacing of let's say five okay then we need this main box to have some spacing from the top so for that what we can do on the main grid on the main Grid or maybe let's add the padding on page level only on the page We'll add up addding 15 from left and right 25 from top and bottom cool save so this is fine after this let's add our login logout button first then we'll work on the center middle section so button text login and for this we'll say grade. row2 cool it's at the very end now we'll start designing it the design first thing we'll say horizontal options to Center okay [Music] then let's have some padding 50 from left and right and five from top and bottom like this then should we have it some small thing or it should be good let's set a height to it height requires 30 okay okay save everything now this login button this should be uh computed if this should be login or log out and it should be on the basis of that property we have in our view model is logged in so here what we'll say We'll add Property Data triggers here so we'll say button do triggers data trigger Target type is going to be button binding is going to be binding is logged in and then value is going to be false if the value is false then seter property text value as register not register log out log out fine it shows log out so it should be opposite if is logged in is true we should show log out and the default will be log okay now let's work on this Center middle section We'll add the UI first then we'll add functionality so for this what we are going to do we will have a vertical St layout because we are going to have multiple rows for the actions so here we'll say grade do Row one it should be first row and on this we are going to add a spacing of let's say 10 and the padding let's say 15 and in here now we'll add uh some design and which will be like uh text and then we'll have one icon and then we'll have some uh horizontal R line at the bottom so for this what we'll do we'll say a grid with the two rows the star and and auto first one is for text and second one is for the no no no yes first one is for the complete text and icon and second one is for that uh the Border we'll use box view for that and column definition also we'll have star and auto so first is for the option text and the second one is for the uh icon at the right okay so on this grid what we'll have first we'll have one label with grid. row zero and grid do column zero and then text this text is going to be let's say my ad options let's see how it looks where is it grid. row0 row definitions vertical strike layout 012 it should have been somewhere here only text color black text color was white by default that should not be the case okay maybe it took some time to H reload to work okay we have this my adoptions then we'll add uh let's say a font size of 18 and then we'll have text color and it is not coming we'll check static resource primary like this and it came okay after this for the first row second column we'll have that icons so here we'll say image grade do row zero and column grd do column 1 and source is going to be we have that right arrow so right underscore Arrow this thing yes now we'll say height request 25 and width request 25 cool and now we'll need to change the color of this IR icon to the same as this our primary color basically so for this what we can do we'll add one more name space of community toolkit XML let's say toolkit equals this one 20122 Maui toolkit and here on this image we'll say image dot behaviors and we'll use icon tint color Behavior which comes from this toolkit name space here we'll say tint color and this is going to be a static resource primary cool now we have this after this for the second row we'll use a box view so box view grid do Row 1 and grid do column isan to we need to uh take the entire width and then here we'll say height equal to one and then color would be static resource primary like this and it is here let's add some opacity to make it faded so we'll say 0.25 okay okay so it looks fine now let's add some spacing between these two so on this grid level we can say row spacing of 10 okay it looks fine now we will use the same design for other options as well we will have uh change password we are going to have only two options but you can uh add other options as well if you want if you can think of any other uh functionality in this app so what I'm going going to do I'm going to move this grid to a separate reusable control content view so that we can use it multiple times and we don't need to repeat everything we just make it Dynamic so text would be dynamic so for this what we are going to do first I stop the app let me copy this grid and then in controls I'll create a new item doet maiet Mai content view with zaml and for this we'll say profile option R okay and in this the content is going to be this grid toolkit is not defined Okay add it let's add the name spaces so this toolkit name space is required there cool we have this here so now this my adoptions this section is dynamic so we need to have one bindable property for this text so here let's create one property first so we'll say public string and text and then we'll create a bindable properties so public static readon bindable property text equals bindable property do create and name of our property which is text written type which is going to be type of string declaring type type of this profile profile oh I made a [Music] typo okay we'll fix it so profile row and then comes the default value we'll use string. empty like this and what is the issue name of text Amity between okay this should be text property so now on this text we'll use our bindable property so it will say something like get value of text property and we'll make it string and then set value text property and value like this everything is fine we just need to rename it so we'll do this we'll rename it from here Pro File option row add it let's stop the API and Prof file options and let's change the name of the file as well okay okay okay okay fine now we need to use this text property in our zaml so here what we'll do we will first add a name to this this name is up to you you can name it whatever you want I prefer this this word and on this grid we will set our bind context to X reference this and now we'll have access to this text property so here we'll say binding text cool now there is one thing whenever uh when we are displaying these options there should be some action when user tabs on these right so for this we need to have some event by which we can notify the the parent of this control that something has changed or not something has changed someone tapped on this uh this row so for this what we'll have we'll have a public event here so we'll say public event event handler and we'll pass the text which has been tapped and we'll change it we'll name it to tab to this tabed event now when should it trigger it should trigger whenever user is tapping on this grid so here what we'll do we'll say grid dot gesture recognizers T gesture recognizer this time we'll use tabed event not command just event we'll come here and from here we will uh raise this event this tabed do invoke and we'll pass sender as this and string e which is the text in this case like this because this is single line we can make it expression body like this and our control is ready to be used now we can use this control on our profile page how we can use it we have this controls uh name space added so we will remove this grid entirely and here we'll say profile row option profile option row like this and on this we can set this text which will be my adoptions so save everything and let's try to run it but before that we need to run our API so API debug start without debugging and API is running now we'll run app mobile app our app is here let's go to profile page and we can see our profile page we can see my adoptions now let's add one more my ad options so this time we'll say change password and it change to change password cool now the action what should happen when we tap on these so for this we know we have this Ted event defined so we can use this and on this second one also we'll use the same thing tab and let's use the same method here and this string e this is going to be the tabed option or let's say option text it should be option text and now we can switch on this option text so we'll say switch option text and then we can add our cases here so first case is my adoptions and the second case is change password like this so here let's see if things are working so we'll say view model dot to what is it on view model okay because we have if you go to base view model we have these methods protected that's why we are not able to access it so let's say public too tasing I made it public so that I can use it oh my God add it so that I can use it here so here we'll say show toast asnc and here we'll say my adoptions tabed and on the second one I'll say change password tabed so that we can see that the functionality is working let's add a weight here like this and we need need to rerun our app okay app is here let's go to profile page profile my adoptions and we can see my adoptions tabed change password change password tabs that means the dynamic UI Dynamic text and the tab event everything is working okay now let's do one thing on this page this profile page let's add some spacing from top for this this section uh this my options change password section so we'll go to profile page on this vertical St layout let's add a margin we'll say zero from left 25 from Top Zero from right uh sorry bottom and okay it looks fine now cool so save save again what is the issue needs to be reilt apply ches okay let's stop it for once add it stop and let me uh restart the API and then Maia or maybe before restarting let's do this on profile view model we have we have that login logout button so we'll work on that login log out button so let's add a command for this first then we'll start so that we can uh see that change so here we'll say private async task and because we have single button so we'll call it login log out yes Sy okay and this is going to be relay command like this and here we'll first check if user is logged in or not so if user is logged in that means we press log out a user is lo not logged in that means user press log out so we when we Press login we should go to login page so go to a sync we'll navigate to name of login register page like this and if that's not the case that means we press log out so for log out what we'll do we will set log out from our Au service service. logout after that we'll move to uh homepage maybe go to asnc like this and this should be name of homepage and this should be awaited log out is a it it shouldn't be it should be we just void save go back and remove this a okay so login log out ising command is ready we can now use it on our profile page so here on this button let's add command we will get from binding it should be login log out command like this is so save everything and let's first run the API and then I'll run app profile not logged in right now we have this login we switch to login let's login so test at test.com and 1 2 3 4 5 6 right this was the correct credential 502 bad gateway isn't API API is running what is the issue then okay D channel. Ms this is not working I am connected to Internet yes stop save run okay now let's log in okay maybe there was some issue with d tunnels. Ms this okay we are here and now we logged in and this section still says High stranger and if you go to profile here we say not logged in and login button but we are logged in so that means the functionalities uh we need to implement is we need to get the actual uh authentication status if user is logged in or not so user is right now logged in and the login in information the token and uh other user info that should be in preferences for sure we just need to pull that information check so let's start working on that so for that what we'll do we need to have some centralized place but before that let's do this go to service common service here we are going to have one event so public uh event event handler and we'll say login status changed event we will trigger it whenever we are uh logging in or logging out okay now let's add a method here so we'll say public void toggle login status and from here we will simply invoke this login status changed event so this and event ar. Mt we don't need any uh any argument any event argument for this stop now let's use tole login status so this should be whenever we are logging in login out and that thing we are handling from our a service so in AU service when we are login when we are using login register a sync after setting this user setting this token we'll say common service dot toggle login status and same thing we'll say after log out so we set the tokken to null we remove the user info from the preferences and then we'll say toggle login status now we need to uh listen for this event change so for this what we'll do we need user information on homepage and on our uh profile page right so first let's go to homepage that means home view model in here we'll inject our common service common service common service now in this common service we are going to say common service. login status changed and we'll say on login status Chang like this now we'll check if do we have o service here no we need to inject o Service as well because from there only we can get the actual loger status and logged in users information so we'll inject all Service as well all service all service and now on this login status changed we will check if Au service dot is logged in that means we just logged in so we will have the user information that is this underscore username so we can fetch the user information we'll say where user info equals uncore off service do get user we have this user now and then we can set a username to user info do name and in the else case we logged out that means you just need to set username equals the default value which is the stranger cool so we are good and we can copy the same thing to our profile view model let's copy this method go to profile view model and here we'll inject our common service common service common service then here here again we'll say common service do toggle login sorry not toggle login status login status changed and we'll use this method on login status changed like this so in this case we are setting username to log not logged in right so let's do this not logged in and we need to set this is logged in field as well well here we'll say when we are logged in we'll say is is logged into true else will set is logged into false now we have this information there is one missing piece now uh I can show you before that let me let's see the changes we just made first we'll see these changes then we'll fix that issue I'll tell you what the issue is and how to fix that app came High stranger welcome profile not logged in and login so everything is fine now if you go to login we are on login page let's login test at test.com 1 2 3 4 5 6 login and now we can see hi test user welcome we'll go to profile test user so Tu initials are coming up test user and now we can see the log out button so everything is working as we expected but now what if I restart the app now it is coming and loading and we can see high stranger if you go to profiles we can say not logged in but why we already logged in right and the login information if we go to our Au service which is here after login we set user and that means we set users information logged in information in the preferences so this information should be there in the preference sale but we are not getting this information when we are coming to the app right so we should use this as well so for this what we'll do in home view model and profile view model both the cases what we are going to do we are going to extract this logic which we have in own login status changed we'll create a helper method private void let's say set user infut and we'll add this logic here for all this on login status changed we are going to directly call this everything is fine now from its Constructor we will call this same method set user input whenever this is page is being initialized for the first time when it is being constructed at that time it will call the set user info it will check if the user is logged in if user is logged in it will simply get its information set the username if user is not logged in then it will fall back to the default value which was this username Str same thing we are going to do in the profile view model here we'll extract out this logic in a separate method so we'll say provide uh private void set user info info like this and from on login status change we'll use this call this set user info and from Constructor we'll call this same method set user info save everything now let's try to rerun the app this time we should have the logged in information beforehand so it it should show high test user and in the profile it should should show that user is logged in you can see tach user that means user is logged in if you go to profile we can see the user is here now if you log out now you can see high stranger and here not logged in now if you restart the app it should show this not logged in state only okay hi stranger you can see and profile we can see that it is not logged in and we can see now login button instead of log out button cool so this thing is working now let's work on favorities page we cannot work because first we need to have some pads added to users favor that we don't have so in order to do that what we need to do we need to First work on the detail page pad detail page so from pad detail page we can add or remove user from this Fab is so now we need to work on this section cool so now let's work on this so on this page there are going to be two Dynamic uh when we say Dynamic interactive uh sections first This Heart icon this uh add to favorities and remove from it and then this adopt Now button uh actually adoption status if this pet is available for adoption or it is already adopted so these two piece of information is going going to be interactive that means observable so for this we need to have these two uh properties as observable property but right now if you go to our detail page page is detail page or let's say details view model we have this pad details DTU which has this complete information and this page this thing is on of in our dto shared project so this is being used from both API and from our Maui app so for this one we should not add observable property and all that directly on this shared DTU what we are going to do in our models folder I'm going to create a a new class for this pack okay and this pad now is going to be observable so here we'll say public partial class pet and this will be an observable object now in here we are going to add all the required information so first let's go to pet list dto we need all these ID name image price breed add this then let's go to P details R and let's get all of these now H ID name image price breed is favorite description gender we don't need this directly on this case because we need just gender display and gender image image so this thing we can get from the DTU itself so we don't need to use this gender we can remove this like this and then comes for date of birth we are not displaying our date of birth we are just displaying age so this complete age logic it can be in the dto itself and we will directly assign this logic from there to this pad so these are the all the property which we need now this is favorties this should be observable so we will change it to be a field make it private and add observable property attribute to this cool and same thing would go with this adoption status so let's change it to be a field private field and we'll add observable property to this save everything and now we are good to use this Pat object in our pad details uh page pad details view model so let's go to a details view model on pet ID changing we have this pad details equals API response. data which is of type Pat details dto now we need to change it what we'll do we'll use this pet object this pet is going to come from our models pet and here we'll say our pet D now we have this pad D and we need to set our pad to this pad D so here we'll say new pet this pet is going to be our pet details object actually this P details and now we will map all the properties one by one now is favorite does not exist on pet details D so we will see how can we uh use this does it exist know right oh it exists p d is favorite okay have it here okay okay then comes name and then price so now we have created a new pet object this is our observable object and we are setting it to pad details now we should be able to toggle the uh favorite status okay so for this in this details view model we will add a command private Asing task and we'll say toggle favorite okay in this first thing we need to check if user is logged in for that we need to inject our o service out service here we'll check if underscore out service do is logged in if user is logged in we'll do the thing or let's do the opposite first if user is not logged in we will display a toast message so we'll say show toast async and we'll say you need to be logged in to mark this p as Fab and we'll return from here we don't need to do anything else now if if the user is logged in then first thing we'll do we'll set pet dot p details. is favorite equals opposite of it if it was uh if it was added to favorite then we'll remove it from fa faite if it was not added to favorite then we'll add it to favorite so we are setting it beforehand before making the API call so that user can directly see the change after that we'll uh make the API call in trage blog so in order to make that call we need to inject our I user API we'll say user API and then in here first thing we'll set is busy to true then we'll make this call so here we'll say await user api. tole favorite async and it needs Pat ID so we will have this Pat ID like this after this we'll set is busy to false or maybe we can set it in okay let's set it is BU to false now if there was some exception we were not able to add this user to fav so first thing we'll set is B to false we will revert the is favorite change which we have done after that we will display error message so we'll say to alert async we'll say error in toggling favorite status and the error we'll use ex. message so whatever it is let's do it after this or maybe on top only rever and we are good with this method now so on this we'll say relay command this should be really command toggle favorite cool tole favorite now we can use it on our page so let's go to Pages uh Details page and here on this image where is it in Flex layout border image heart this one in here on this border itself we'll say border do gesture recognizer tab gure recognizer command and we'll get the command toggle favorite command like this we don't need to pass any parameter now we will modify this image so what we are going to modify in this is we will add a behavior to this no not Behavior we will add trigger to this we'll change the now yes we will change it we have one image forfill right so service resources uh images and Heartfield we have this image so we'll use this okay so image. triggers here we'll say data trigger Target type is going to be image and the binding should be binding uh pet details dot is favorite and if the value is true then we'll set Setter property Source the value is going to be hcore field so save everything toggle favorite command I already added so everything should work now API is running no API is not running so let's run the API first start with the debugging then I'll start the Maui app we are here let's go to detail page we are on detail page and you need to be logged in to mark this pet as favorite this section is working let's log in go to profile login test at test.com password login and now let's add it and we can see this right it got added if we remove It Go to this again we should see this oh this section is still remaining so for this if we have already added a pack to favorite we need to get the information of that as well so for this if we go to our details view model we are fetching the pad details from pads API which does not need any uh authentication user ID so one way is we can pass user ID from here but that is not uh going to be a good approach Reon if this is public and if someone added any random user ID so I can see what all pets you have added to your favorite is right because this URL is public that's not what we want so instead what we'll do let me stop the app let's go to the API and here in pads controller we have the pad details we'll make a copy of this we'll add it to users controller we'll fetch it from here as well but this time let's inject Pat Service as well in this Pat service Pat service P service and this one p get pet details asyn H we will get one optional parameter user ID so this is in service so service is going to be called from our application only so we are good with this here what we'll do after setting this bad details and all this maybe after setting pad DTU as well here we'll check if user ID is greater than zero that means if we have provided user ID then we'll do something else as well and that's something else is we will check if a wait context dot user favori is do NE sync if in our user favor is table if we have any entry for this user ID user ID equals this user ID and UF dot Pat ID equals equals this Pat ID that means if this pet is added to favorities for this user then what we'll do we'll say pad DTU pad DTU do is favorite equals true and if we have not provided it so the default case would work as it was working before so now from our user controller after passing Pat ID we will also pass user ID the URL for this is going to be API sluser slash uh it should be something here right API user let's add pads in between but these are not user pads right so the URL we can have it although we can have it anything whatever we want but let's do this view details something like this okay so the URL is going to be view pad details let's do this API SL user SL viad details SL Pat ID okay this is going to be get and with one parameter Pat ID and we are good let's add this to our refit client so on our ma side I user API we will add this method here like this and the URL is going to be and this API SL user SL viewpad detail and this cool and this API response this should be this shared d. API cool so we have this here now we can use this now this should be conditional what I mean by conditional is if we do not have user ID then it is not going to work it will throw exception so on a details view model here what we are going to do instead of directly calling this we will add a condition here the condition is going to be Au service dot is logged in if user is logged in then we'll say users API dot get pad details async and we are going to pass this value and if user is not logged in we will get it from the main pets API so this is the authenticated request a wait the first one we are getting from users API so we will have the E favorite status ready and second one is for non-authenticated user from the public Pats API so here we do not have we will not have his favorite status so it will be false and that makes sense if user is not logged in how can we calculate that if user has added this to favorite or not cool so I think this is fine now if we run both API and uh mobile app we should see it in action so let me run both of these and we have some error the error says iPad service iPad service let's go to what okay we need to modify the interface uh this Pat ID here we will say in user ID equals z like this save and now we should run now we are already logged in so it should show login status we should see our high attach user and now if we open that particular pad we should see that already added to the fa it was budy right and we have some problem oh my God the same issue I users API we should not have this route constraint ID so let's run okay buy and what is the issue here Ur path API users must start with a slash okay this I am missing this slash restart okay test user bu and this time it 401 unauthorized and why so we are already logged in right let's try to login again maybe token is expired we need to handle this case as well now if you go it should simply show the details without for without login not loged in users now let's login test T add test.com 1 2 3 4 5 6 login I test user bu 500 error in fing pad details intern server error let's add the breakpoint to check what the issue is or maybe we'll have it here yes we have ER it says Pet Service while attempting to activate Pat adoption Maui what is it system inv pad service while attempting to activate pet adoption Mar controllers user controller what do you mean we already have Pat service ready and that is being used from other controllers right so from Pats controller we are using pad service oh iPad service my bad it should be iPad service the interface let me stop the API save everything run the API and then I'll run mobile app okay app is here let's open 401 does the token we are not saving the token or is there some issue okay we'll check it but first let's see the thing we are trying to achieve so login test test.com 1 2 3 4 5 6 login buddy and cool we can see this selected now let's add some Shadow to this so on Details page and where is our Details page Details page on this image let's have some default Shadow so it will say image do Shadow just have a default Shadow okay we can remove it from faity we can add it go back open some other pad select it so this is working now let's see what the issue is with when we first come to to this it says 401 and why so let's check where is our common service we are using this token and when we are coming for the first time at that time we are not setting token so token is empty token is null that's why it shows 401 so let's think where we can set this token so when we are setting the user information at that time only we should set it right so from home view model we are setting the set user info after setting username we should set we will say common service. set token here we can access user info. token same thing we'll do in profile view model so after setting all these we'll say common service. side token user input. token cool so save now if we restart the app it should open in the logged in status and we should be able to directly fetch the pad details with the actual information that uh pavate information because this time the token should work okay it is loading if we go to Buddy and we can see this that means that issue is fixed cool this is not logged into faity so we are fine with this okay let's add couple of other pads as well Cooper add fine now before working on adopt section let's work on favorite page now we have login status ready we have our users API ready we have everything ready we have that functionality to toggle the fav that is also ready now we can directly work on this so on this screen we are going to show the list of pads which this user has added to its fabes okay so for this first let's toop it and let's create a new view model let's close all the tabs close all tabs go to mobile view models add a new class fav is view model and this is going to be public partial class and the base class will be same base view model save everything close everything save fine and in here first let's add the Constructor so we need our users API because from there only we can uh fetch the list of favorite pads for this user then we need to check the logged in status on this page so we'll inject all Service as well all service cool now we need to display the collection and we can uh remove some pet from this collection so this collection is going to be modified the items are going to be removed from this collection so this time we can't use I numerable we should use observable collection here so here we'll say observable collection of of type pet and let's say favorities or favorite pets oh let's call pads only with a default value of new fine now we will have that initialize method so we'll say public asnc task initialize a sync we'll have try catch finally here in try first line we'll set is B to true in finally we'll set is B to false in exception we will display an alert message error message so we'll say await show alert async and here we'll say error in fetching pets and ex do message like this then comes main part is busy here we need to first check so maybe before is busy or at the so let's come to the out we don't need to be in try C just first check if user is logged in or not if user is not logged in then there is no point of fetching the favorite pets so here we will say if user is not logged in we'll show toast message so I will show toast and you need to be logged in logged in to load your favorite pads like this and we'll return from here cool and if it bypasses this that means user is logged in now we'll say where pads equals here we'll say uh let's call it API response API response equals a wait user api. get user favorite asnc now we'll check if API response. it success or l just show alert message here we'll say p response. message if this call was successful then we know we will have a data for this pad using AP response. pad uh dot data basically but it will give us Pat list d right this gives us Pat list D and on Pat list DTU we need to modify we need to uh notify change for is favorite and on this screen we are not showing all this thing so let's create a new class for that small subset of this pad so we can say pet small minor or let's say pet sling so this is a lightweight version of this pet and we'll use observable object and this needs to be partial for this and in this what we'll do we'll have ID name image and is favorite status just these things nothing else observable property what is the issue observ property does oh this okay so P slim let's go move it to its own file and now we are good now we can use this so in our favorite view model here we'll say We'll change it to Pat slim object and now we'll say favorite P equals uh API response dot beta well let's do this let let's directly set this PS equals API response. data do select here we'll say p goes to New Pat slim object and then we'll set ID to pet ID image to p. image then is favorite so P dot we don't have his favorite on pet list DTU at list DTU so that means no no no here we can directly set to true because we know this is related to user favorite only the list will give only favorite is okay then comes price oh the price we not what was the other thing we were displaying here B slim ID name image is favorite ID image is favorite and name so we'll say name equals P do tool so in pads we are not we cannot directly add this what we can do we'll say new observ collection we can directly add it here this data this okay so we are good now cool let's inject this to our favorite page Pages favorites page inject this view model view model let's add The Binding context binding context to view model then let's override on appearing and in here we'll say await view model. initialization syc and then we need to register these to our di dependency container so let's come here and here we'll say services. add transient favorite is view model do add transient favorties page save everything add it and then on fa page let's add all the name spaces let's get those from Details page okay and then let's set the data type for this page X data type this is going to be favorites view model so save and let's stop everything so save save now let me first run the API then I'll run the mobile app okay let's move to favorities page and let's start designing this so first we'll have a grid top level Grid then inside this we are going to have a scroll view this is going to be a container for our collection view so we'll say grid. Row one and let's have a padding of five inside this we are going to have a collection view with the item Source binding and pads cool and the layout for this we are going to use we'll say item layout items layout and this is going to be a vertical grid with two columns cool now we'll Define our item template so we'll say collection view. item template and data template and data type is going to be our pad slim cool so now first let's have a label we'll set the name binding name so that we can see this thing is working and we can see five pads which are added to Fab for this user so we can see this now let's start designing so inside this first thing we'll have a border and then we are going to have stroke shape as round rectangle round rectangle and we'll have 50 from left top 50 from right top and then zero Zero from left bottom and right bottom okay on this we don't need stroke thickness so stroke thickness zero and then let's have some margin of 15 now inside this we are going to have a vertical strike layout in this we are going to have a grid then we are going to have a image so the source is going to be binding image now we should see the images and we can see these cool now this image let's set the aspect fill and then let's have height request of 150 we don't need to set the width because we have this vertical grid layout with two columns so the width is going to be calculated automatically by this item layout we just need to set height and it is good it is looking great to after this image we are going to have uh that icon that is favorite icon so for that what we are going to have we say border and we are going to use one style which is going to be static resource icon B container so inside this border we will have our image with source and by default we should have part fi because we know this is fav so so H okay okay now on this border let's move these two vertical options uh and to the bottom okay and let's so horizontally it is Center align only right yes let's have some margin margin we'll say minus5 okay now it is looking good cool H after this let's work on this image first so on this image we are going to add our triggers and this is going to be data trigger we'll set Target type uh image and then we'll use binding and this is going to be binding is favorite and the value we are looking for is false if is favorite value is false then we will use a Setter and we'll set Source property to Heart image this normal image not filled not this uh this red tomato color this one okay now on this border let's add a command to toggle this favorite we can tap on it and it will be removed from our fa list so for this we'll say border do gesture recognizers tab gesture recognizer and here we will have a command command binding Source this is going to be relative source and ancestor type it will be X Type faves view model and the path is going to be we have not defined Command right for this uh toggling the status we have not defined it okay we'll Define we can use the name so we'll say toggle favorite command okay let me copy the name name we'll add it to the our view model and here we need to provide our Command parameter as well this is going to be binding and this will use ID which is Pat ID cool so this is done now H now if you tap anywhere on this image we should open the detail page right before that let's add the pat name so after this grid inside this vertical stack layout we add a label with the text binding and Pat name we'll say font size 18 font attribute bold and text color as a static resource primary and horizontal options at Center cool and on this vertical stack layout now we can have some spacing so let's have spacing of five and it is fine now okay okay now on this data template on this border let's have border. gesture recognizers tab gesture recognizer and in here we are going to use one command and this command is going to be uh we have defined this command on the base view model right so if you go to uh favorites view model okay let's do this first let's add the command for toggling the status so here we'll say private async task task toggle favorite a sync and we'll get pet ID as a parameter we can say relay command here and now we can call our API to toggle the St so here we can say try and we'll set is busy to Pro after that we'll say await users AP I toggle faving P ID okay now we have toggled that means we have removed it but before that let's do this let's find this pet from our collection observable collection so we'll say word pad equals pads do first or default p goes to P do ID equals equals Pat ID and if this Pat is not null then we'll do all of these things although we know this is not going to be null okay now we have this pad after setting is Vis to True we'll say pet do is favorite equals false then we'll set each bu to true then we'll make this API call and after making the API call we will remove this pad from this collection because now we have removed this pad from users favorite list and we are on favorite is page only so this pet does not belong to this collection anymore here we'll say pets do remove p and we are good now after this we can say in finally we can set is Vis to false again okay so this command is ready then I was saying on the Bas we have this go to Details page command we will use this command to navigate to the detail page so for this the same thing we have on all pads page so let's copy it from there so we have this go to Details page command this one let's copy this we'll go to favorities page here let's paste it binding ID Source The View model is going to be favorite view model in this case and we are good after that on the main grid we'll set our activity indicator with is running we'll set to binding is then vertical options Center horizontal options at Center and color static resource primary and then there is one more thing in the favorities view model when we are initializing the data okay we are setting it directly so we should be good okay let's see if it works so I'm going to restart the app app is loading and app is here let's go to fabes page we have activity indicator and then we do not have any anything and why we don't have anything that's because I have added a breako we came to all pad's page this page takes time because we have this collection view which has the items as observable object it came here I did not add anything rebuild and apply changes API is running response status code does not indicate 502 bad gateway that means again uh the dev tunnel is not working we need to wait restart when we are using da tunnel then this 502 error we do not have control over this 502 this is from Microsoft side okay we'll go to fabries we hit this break point and whenever I'm pressing this F 10 there is some issue let's add a break point here and we'll continue from here I am not making any change fa it is and we have data so AP response data we have five deurs and this is white is not loading let me first stop the API sometimes uh that H reload uh message of if we have API running okay then we have one problem this is not updating and that's because this is an observ collection we are directly setting values to this so we have two approaches either we can add observable property on this then we need to modify it to have a proper uh the variable and the second approach could be instead of directly assigning value to this we can add these items to this collection so let's do the observable property option so here we'll say underscore pads and we'll set it to default like this now it should work save everything run the API start without debugging and API is running now we can run our Maui app and this time we should be able to see the all the favorite these pets is loading and we can see this cool if we tap on it we can see the details go back and if we tap on this I'm removing coers so I'm tapping on this and this got removed then I'm removing buddy from here and we are good if you go to home if we go for bu now it is it got removed and if I add it again from this screen if I go back go to fav is here I should see the buing so that means this functionality is also working so now our faes page is also done cool login log out is was already working for my adoptions to work for change password we'll have a simple uh prompt from there we can change the password so before doing that we'll work on my adoptions and for my adoptions we need to work on adoption part first so if we tap on this pad detail we need to work on this adop Now button right so for this adopt now we already have API ready for adoption so we are going to use that API first let me close everything now let's go to details view model and on this view model we are going to create a new command for this we'll say private Asing task and we'll say adopt async okay well let's say adopt now a sync this is going to be a relay command now for the logic first thing we'll check if user is logged in so we'll say Au service do is logged in if user is not logged in then we'll display uh instead of displaying toast let's display it confirm as so show confirm ASN title is going to be let's say not log in and then message mass is going to be you need to be logged in to adop aad okay and after that we'll have a new line so environment. new line and then we'll ask user if uh user want to go to the login page so here we'll say do you want to go to login page like this okay then okay button and cancel button so okay button is yes and cancel button we'll use no so we're displaying a confirm box so here we'll check if user pressed yes user confirm that uh he wants to go to the login page so we'll say a wait inside this we'll say a wait go to async and here we'll say login register page login register page like this name of login register page name of login register page cool so we have these two if state ments we can merge these so we'll say like this like this if user is not logged in and this then show this and return from here or we can add else condition let's return from here okay if that's not the case then what we'll do we'll say is busy to True first thing then we'll add try cach block and in here we will patch our API response equals of wait users API do adopt Pat async and we'll pass the pat ID P ID like this after that we'll check if API response dot is Success if this is Success then we will go to one page that uh thank you page so kind of that will display that thank you message or maybe uh successful message that adoption is successful so let's create that page we have not created that page right adoptions all these yeah so let's create a new page new item Mai ma content page ZL and here we'll say adoption success page adoption success page fine okay so if the it was successful we'll say a wait go to async and here we'll say go to name of adoption success page cool and if that's not the case that means uh the adoption process was not success there was some issue so then we'll say a wait show Aller async error in adoption and what is the error that error is going to be API response. message like this after that we'll set ISB to false and then inside catch block we will display error message error alert here we'll say ex. message and then save is vit to false okay we are good adoption process is busy true cool so this should work now add it we are going to use this adopt now so after adoption we should modify the status okay we'll do that later when we'll Implement a signal AR we'll do this then then we just created a new page this adoption success page we need to add it to the Maui program appell we need to add it to routing so here in ell we'll say routing do register route and here we'll say name of adoption success page and type of adoption success page like this save now we can bind our adopt Now command on this button so here we'll say command binding adopt Now command cool to save everything rebuild and apply changes now this adopt Now button it should work let's see okay app is here now if we go to any detail page we can press set up now and we could see that uh what is what activity indicator then it move to this page and this page should be of course it should be adoption success page only we'll design this page later but for now let's go back go back and if we open this pet again this Rani it is still showing adopt now but we already adopted this pad that means something is missing so we'll go to details page. ZL on this button we are going to add triggers here so button do triggers data trigger Target type button binding is going to be binding uh Pat details Do adoption status and the value is going to be if the value is adopted then we'll use a seter property and here we'll set text to uh value we will use adopted it is showing adopted then with this one we will set one more property that is going to be is enabled and we'll set it to false so if pet is adopted button should not be enabled if you open any other we can see adopt now and this is working if we'll adopt it if we come back it should show is not triggering why discourse adopted it is taking some time maybe because we just made change H reload is not working properly okay so the default case this should not be adopt now right because when we come to any one it shows now but it should come when we have the data and we have the actual status so for this what we'll do we'll change this or maybe before that let's add one more data trigger this time the value should be available and here text we'll say adopt now and is enable abled value we'll set it to true and the default text we are going to say checking or we could say dot dot dot to save everything open any page we should see those three dot dot dot and by default let's say is enabled to false and then is enable true if the adoption status is available let's restart the app okay it is coming dot dot dot and then adopted and chandani dot dot dot adopt now cool so this is working great now let's work on this we'll say adopt now let's work on this page so for this page adoption success page what will say the title is not coming on this page tell. nbar is visible true no this is this page only right yes this is this page oh it is coming as model it should not come as model so we'll say shell dot presentation mode just animated okay you see we have this issue we'll fix this as well we need to modify the status of that pad right now error in adoption mirror is already adopted that means API this functionality from API side is also working if we try to adopt some pet which is already adopted we are going to have this V okay so let's fix this thing first so in our details view model after getting the pad details we'll say pad detail dot adoption status we'll set it to adopted like this let's rerun the app okay let's open details adopted bu adopt now adopted it came here it again came as modal an we go back this is adopted but why this button is still enabled adopted this is adopted so is enabled should be false why this is not working okay we'll check why this is not working but right now the main problem is the way it is opening that success page missing somewhere what am I missing if I go to app shell app shell here I do not have any special setting nothing right yeah nothing then on this adoption say SP never is visible through title adoption shell. presentation mode animated because it was using the modal animator okay to check this let's go to details view model and we'll directly go to this page we are just testing it I'm adding this line first then I'm ret turning from here so that whenever we press that adapt now it should directly navigate to this page we need to check what the issue is with this page and then we need to design this page so let me restart the app okay go to some pet add up now and it again came from the bottom on uh what is the issue name of adoption success page let's say background color my add yes everything looks fine shell. Nar is visible true presentation mode animated modal not animated we don't need this modal if we say not animated then what will happen so maybe this is getting this status yeah this thing is working not animated it is not animated this time but somehow it is coming as model because the previous page is like this I don't know do let me know in the comment if you guys know what is happening here for me I don't know what is happening I maybe uh check maybe this is some issue from the Maui side or maybe this is the expected Behavior I don't know if we are on a modal page and from there if we move to any internal page then it comes as modal only maybe this is the default Behavior I have not tried it before so if you guys know about it do let me know in the comment for now we'll just use as it is working so let it be on this page what we are going to do we'll simply have a grid in this grid we are going to have a vertical stack layout y grid we don't need grid we can have vertical stack layout we don't need uh uh that any activity indicator on this page right right like that okay even if we don't need activity indicator yeah let's not use grid we'll use vertical St layout and in this vertical St layout we'll set horizontal options at Center vertical options at Center and then I'm going to have a spacing of 25 and now I'm going to have a image and which is going to be I have this image which is undraw confirmed which I have downloaded from android. then we'll set at height and width so height of 250 and width as well 250 okay now if you go to the page adopt now we can see this image fine after this image I'm going to have a label with text we'll say adoption successful and then I'm going to say font size 30 font attributes bold and text color static resource primary color Co after that I'm going to have a button with the text let's say Explore More packs something like this it is here now on this I'm going to use uh should we use the same style no let's do this we'll say padding zero and the 15 and then or maybe we can use that R button only right so let's say this style static resource rain plan yeah this looks fine this looks great okay save it and when we tap on this Explore More button it should navigate to the homepage so on this I'm going to use click command click event not command here we'll say await shell do current dot go to I think I don't have anything on this page so I'm not going to use view model for this page so here we'll say this then move to homepage like this cool so the basic page is done now we can add some uh animation to this image and this text so for this what we can say we can do let's add some animation on this image so for that we will add a name for this let's say image only and then we'll use a default scaling on this Z 0.1 so very small image now we'll use this image field and we'll override a method here on appearing and here we'll say a wait first let's say task. delay 100 so that we can see something and then we'll say image do scale 2 it is initially uh 0.1 we will make it 1.2 so uh zoomed in effect then we'll say the length we'll minimize the length so that it look it animates very quickly a wait then let me copy it a couple time then I want it to come from 0.1 to 1.2 then let's move it to 0.5 half of the size then again 1.2 then let's copy these two lines and paste these three four times and then finally I want it to be one which is the actual uh size okay so let's rerun the app it is coming let's open ad up now and we can see this this is a lot let's remove this then if you Tye on explore more pets then it move to homepage so that means this flow is is also working now we are good now we can go to our details view model and we can remove this thing which we have added just for testing cool save everything stop and API must be stopped now let's stop it to stop everything now next thing is we will work on are adoptions page my adoption where we are going to display the pads which that particular user has adopted okay so for my adoptions let's close all tabs first then we'll create a view model first so in our view model folder I'm going to create a new class we'll say my adoptions view model this is going to be public partial class with base view model as the parent class base class then here we'll have a Constructor in this we need all service and we need our users API cool now in this we are going to have one collection where we'll display our adoptions user adoptions so that I'm going to say private I enumerable of pad list dto and I'm going to say my adoptions and then with the default value a numerable of empty this and this is going to be an observable property cool now we are going to have our initialize method so public async task initialize a sync like this here first thing we will check if uh user is not logged in all service dot is logged in if this is not true we will display alert uh toast show toast asnc we'll say you need to be logged in to see your adoptions and we'll return from here now if user is logged in we are going to patch user adoptions so we let try catch we'll say is busy to true then let's say a wait task. delay of 100 to check if the activity indicator that is displaying and here we'll say word API response equals a users api. getet user adoption sesing okay now if API response. it success is true we can set our my adoptions to API response. data like this let's use the finally block where we'll say is busy to false and then in this exception we'll simply say a wait show alert asnc we'll say error and ex message ex. message and same thing we'll do in else case if the API call was not successful here we'll say API response. message Api response this and we are good cool now let's register this my adoptions view model so we'll go to our Mau program and here we'll add this with the shell route so we'll say services do add transient with shell route first we need to have our page so my adoptions I do not have the page for my options let's create a page first oh this is adoptions right so the name is adoptions adoptions page and the view model is my adoptions view model the route we want is going to be name of adoptions page cool save everything now we can go to our page which is this adoptions page and we can inject our view model we'll say view model then we'll set binding context of this page The Binding context equals to view model then we'll override on appearing and here we'll say await view model do initialization like this and cool now let's add the name spaces for this page first let's set the title it is going to be my adoptions the name spaces we can go to all pads page from there we can copy all our view models all our name spaces then let's set the data type of this page so x. data type this is going to be my adoptions view model and for the design we can use the design we have on all pad space so we can use that complete design I'm going to use that and we just need to fix some of the things don't need the refresh view on this page so we can get rid of refresh view first we'll cut this out remove this refresh view add the main grid grid inside grid so we don't need this grid as well because we needed this grid on uh all pad space because we were displaying this label pull to refresh so now we can simply get a scroll view we move this grid as well and now we should be good okay the only thing is we need to First change this to my adoptions item source and then there should be some command which is all pads view model this should be uh my adoptions view model everything else should be fine great save everything stop it stop the API fine save everything now we need to move to this page and that we are going to uh come from this profile page right so on profile page we have this profile option Road tabed here either we can have this thing in view model from view model we can call go to a sync that is not accessible so let's make that Public public first go to a sync method and here we'll say V model. go to a sync and here we can say name of adoptions page like this cool so this should work now everything should work now okay before testing this let's work on this change password as well so for this change password what we can do let's have a method here we have profile view model okay let's add that in this profile view model only so we'll go to profile view model and here we are going to create one more method private ASN task will say change password as sync okay and this is going to be a relay command here first thing we will check if user is not logged in so we'll say do we not have what service we have it if off service dot oh underscore off service dot is logged in if this is not true then we'll dis display the same message we are displaying on our adoptions page view model my adoptions view model this thing this thing so you need to be logged in to change your password let's say this or you might remove this option Al together if user is not not logged in or maybe you can disable this option it's up to you how you are approaching this so you need to be logged in to change your password and then we'll return from here if user is already logged in then we will have one prompt here for this we'll say a wait tell do current no not shell do current we say app do current dot main page dot display prompt AC so the title is going to be change password password then comes message so here we'll say change password only then comes accept button placeholder cancel button so let's add placeholder here we'll say enter new password and then okay cancel this should be fine so let's do this let's store the value so we'll say new password equals this now we'll check if this new password is not null or whes space then we'll change the password if that's not the case we will not do anything and uh let it be whatever the default flow is now for change password uh did I create controller action method for this so login register let's do this in user controller okay let's create new method here so we'll say public casing task of API response and we'll say change password and now we have a problem this should be hdb post and URL is going to be let's say change password now we are only getting one value so that is going to be a new password now first let's go to Au service to create this method so we'll say task of API response change password as sync and here we'll say string new password password and then inside this s Service it will come here we will say public async task of API response change password passw is sync string new password and we should have user ID as well so we'll say int user ID and let's move the second this password to the second parameter okay let's copy this change password okay now first we'll get the user from the database so we'll say DB user equals a wait context dot users Dot first. default is sync will say you goes to U do ID equals this user ID user ID now we'll sa DB user is not null then set the DB user dot password equals new password and this time we need to track the changes for this because we want to modify this hashing this and then we can simply say a wait context do save changes ising like this like this if that's not the case from here we can return API response do success if that's not the case we'll return API response do fail with invalid request some generic message change password ising change pass is think we can use it directly we are good now let's go to users controller and here we can directly call a wait users not us but all service we need to inject o service we'll inject it all service High o service actually so all service and then we can use our change password method on this Au service. change password async user ID and new password everything is fine there is one issue this string new password because this is a post Mass third HTTP post uh it is going to get the value from body and string is not directly we cannot consume string value directly from body so for this I have created a dto and share dto single value dto this dto so this is a record class so whenever we need any single value which could be maybe integer or single string value single primitive value with string so if that's the case we can use this type so here instead of using this string we will say single value d of type string and then here we'll say new password. value which will be the actual password value so we can use it like this now let's add this to our I user API refit uh interface in our mobile Maui side to Services I user API and let's copy the the signature like this and here we are going to say post and then slash API sluser slash change password change password like this and now we should be good we can directly consume this change password Asing okay let's go to our uh profile view model right we were on profile view model where is it profile view model here so now we have this new password value first thing we'll say is busy to true then we'll say a wait users API I don't have user API here okay let's inject user API on this user API I'm going to call change password as sync for this I need to provide new single value dto with new password after that I'm going to set is B to FSE and then I'm going to display a toast message so show toast asnc that passord change successfully something like this save everything and we can use this change password command now from our users sorry profile page right so if we go to our profile page profile where is profile page profile page code behind here from this change password Here we can say view model Dot change password command dot execute async and we don't need to provide any parameter right right so we can say n Save everything everything is in place now so my adoptions and change password both of these functionality should work okay let's first run our API we made change in API as well so we'll run our API then I'm going to run our our mobile app okay app is here if I go to profile page change password I can see this if I cancel it nothing will happen if I say 1 2 3 4 5 6 7 okay password changed successfully if I go to my ad options on my ad options I can see these four Ps and if I tap any of this I can see the details with adopted now let's do this log out come to profile tap on change password you need to be logged in to change your password fine now if you press my adoptions it navigated to this page and it said it displayed that toast message you need to be logged in to see your adoptions so this means right now complete functionality complete app is working with all the functionalities right what I demoed you everything is working fine there's only one missing piece now and that is signal R integration so that is we are going to do next okay so before uh working on Signal R let's see how the app is looking on iOS so I'm on my Mac now I have simply cloned this repo pull the changes so let's run on Android device first so in I'm on Mac my Mac and vs4 Mac does not support da tunnel so what I am doing I am running DB tunnel this API project on my Windows machine and I have simply checked the same uh what I mean I I'm using the same URL in my this Mac so it is connecting to Dev tunnel and that Dev tunnel is connecting to my windows uh API basically so this is how it is working right now so Dev tunnel is supported on Mac OS as well but using command line utilities so if you want to know about it maybe I can drop the URL link of Microsoft offic documentation in the description box so you can check that out you can enable that or if you want to if you want me to create a dedicated video for this I can plan a video for this do let me know in the comment if you want to see how can we uh Implement and connect to Dev tunnels using Mac W I can plan a video for that all right and if you're not willing to do this if you are working entirely on Mac then you have that option maybe you can just to run the API locally using stps Local Host and the refit configuration is going to change a bit and for that I have already created a dedicated video so you will find that video maybe the previous video only from this video so in that video I showed you how can you use Rapid client to connect to https Local Host API so you can try that one and if you will use https Local Host everything think all the calls will work but this uh the image these are not going to work so in order to work with images what you can do you can go to let me open my GitHub okay so this is my GitHub and on here I have this repo P option Maui so this does not have the complete code it just has the simple uh you could say the starting point and in this if you go to API and then we have triw root images pads here we have all these images so what you can try you can just grab this URL copy this and then go to visual studio and in here if you remember in our API in our extension we have mappers and selectors so mappers and selectors here so you can modify these two places and you can paste the complete URL like this or we can do this okay let's do this let's make your life easier so in app constants after this base API URL I'm going to create another constant so I'll say public con string and base images URL and I'm going to paste it and I'll remove images SL pads this section okay so now the by default okay first let me use this base images URL in both of these files so instead of Base API URL we'll say base images URL then in mappers I'm going to say the same thing base images URL now for me because I'm running uh this okay let's do this copy paste and I will leave it here so that you can directly use it uncomment this if you are using Local Host https API okay and then I'm commenting this slide so the default I'm going to use the same base API URL only like this so I'm going to use this one I have commented this out so if you are using Local Host https then you can simply comment this line out and uncomment this one then it will behave same okay so let me save everything cool and let's rerun it will run without any issue but let's still run so we saw that uh the onboarding screen and then we'll check it was looking same okay app is coming and we are on homepage okay because we already shown that on boarding screen okay that is fine and this is not going to work API stopped let me run the API on my Windows machine so the dep anel we created that is somehow not working that page keeps on loading so it is not working so I have created a new Dev tunnel and run it and then I change this URL to that new Dev tunnel and then I just run it and now we can see this but we cannot see the images why soel space API URL did I change something let's see in API mappers B AP URL images pads p. image yeah it should work base images URL which is base API URL only let's try to hit this in browser see let's move to some other page no image no image okay let's try this URL in browser slash images SL pad SL img1.jpg continue and we can see this image what is that let's try to rerun the app or maybe let me clean the app then I'll clean this project and then I'm going to run it so it was still not working then I try to check what is the image URL it is getting so when I'm printing this it is getting this URL so this is somehow pointing to the old Dev tunnel C URL but it should have mapped to this one so maybe it is getting it from cash so I'm going to uninstall the app and then starting the app again then let's say okay so app is here let's see explore we move to login register page we can use switch to login switch to register so this is working fine let's log in with the same credential test test.com all fields are mandatory this is coming 1 2 3 4 5 6 login incorrect password because we changed the password right so it is 1 2 3 4 5 6 7 and we are on homepage [Music] now H what is happening what is happening let me check the API no AP must be running because we just tried login registers all p go back to homepage it it's still loading okay and the URL is still the previous one why we are getting the previous URL mappers base image URL oh oh my God so did you guys get the issue here the issue is I have modified this uh app constants in here but uh this current APP it is actually connect connecting to our API using Dev tunnel and this project is running on my Windows machine and at that machine I have not modified this URL so that's why it is connecting to this URL okay let me make these changes on Windows machine as well okay so I have made changes there I have run the API now let's try and we can see the data okay let's remove this section which I have just added on homepage so it was name right name save everything and we are good cool homepage is working all pads page it is working favorities page it is working profile change password my adoptions detail page adopted so everything is working the design is same so everything looks great here let's stop it now and let's try it on iOS so I'll select my iOS emulator and let's run it it should freak out most collection views just don't work like the way these works on uh Android let's close close all the pages and let it run then we'll fix all the UI issues okay it is [Music] coming all right so app is loading and we this image this should be uh the rounded shape but this is not and apart from this everything looks fine on this screen let's continue we'll fix this here again image should be arounded but this is not switch to login register things are working fine here okay these are the default uh view so I'm not going to modify this but we'll definitely going to modify going to fix these images let's log in so test test at test.com 1 2 3 4 5 6 login activity indicator incorrect password 7 2 3 4 5 6 7 login homepage and okay this is pretty bad okay we'll fix this let open the detail page and on detail page this image alignment is not right and then this this main image is not in that uh rounded shape go back go to all pads first I'm just looking around the complete app then we'll fix all the issues one by one this is looking same right there's no issue on this screen P to refresh this is working favori is okay this is also broken profile this looks fine only this test user this is not coming right so T is clipped from this laptop change password it is coming my adoptions and this screen is also fine okay okay let's start working first we'll try to fix our homepage so let's open homepage so the collection views Carousel views and specifically if these are inside grid and all these alignment and spacing this this is mesed up in net Maui there are couple of open issues for this and I think there is something coming in net 8 to fix this sizing especially for iOS but right now we are using Net 7 and net 8 is not yet released so let's try to fix it using some workarounds so on homepage this main carousal view so the problem is this collection View and caral Views these cannot uh calculate determine the height and width of the screen or how much space It should take so we will provide the exact measurements what we need so here we have this border which is of height 250 and width 250 then we have these two labels name and uh price so for Border we know it is 250 and for name and price let's consider 50 more so we'll use 300 on this carousal View so we'll say height 300 so the height is here this is fine now where is name and that we cannot see the name right let's restart the app and then hot reload does not work properly with Carousel view that we already saw when we were building on Android okay now we can see this this is fine then let's go to this popular pads the second section so this popular pads here we are using this item template which we have defined above so this is border of 100 and then one label so it's 100 and let's take this label at somewhere 25 so on this collection view we will set height of let's say 125 okay and the same thing we'll do for the second one this collection view will set height request 125 and we are good cool so this thing is fine now we just need to work on making this rounded so for this what we are using right now we are using border and then image so border somehow uh does not working in our case so instead what we'll do we'll change border with frame so we'll use frame with same height and width so height was 250 and width was 250 and then we we have Corner radius to make it rounded we will use half of the height and width that is 125 and then this grid do R zero tool and inside this we will add our image add the image and then we are going to comment our border let's restart okay okay okay this is rounded but there is some issue image is coming out of this Frame so for this on the frame we will set a property which is is clip to bound so using this we'll say that content should not overflow from the bounds from the boundaries of this Frame so we'll say is clip to bound true cool okay this is fine let's use the same thing for these two sections the popular Pat and you may like so for the we are using this data template let's do the same thing here so we'll say frame with the height request of 100 width request of 100 and Corner radius of 50 and is clip to bounce through and then we'll simply copy the same image paste it here and we'll command this border okay let's restart okay so app is here and this is looking fine cool All Pets was working fine then his favorite is pad details I remember there was some issue with frame that's why I stopped using frame the this tab gesture recognizes this does not work and at that time I was using Windows machine for Android only so maybe on Android this does not work okay we'll fix this later but on iOS this home screen is fine after this let's do the same thing for this detail page I'm going to take a quick break then I'll be back and then we'll work on this page okay so for this one let's go to detail page Details page and we'll do the same thing first for this image we have this border no not this border we have this border we will add a frame here frame grid. Row 1 then height 300 width 300 Corner radius uh 15 and then is clip to bound true and inside this we will simply copy our image copy and paste and then we'll command this border we'll remove this eventually but right now I'm just using this so okay we need to restart the but before that let's fix other things as well so this right uh this image the heart image let's fix this so this image not left Arrow this one this heart so for this we'll say horizontal options as Center and vertical options as Center so it should be moved to the center it is not going there why so let's restart the app if it didn't work then we may need to add the uh height and width to this image but for now let's see if it works app is here let's open the details and cool so this is fine but this image uh This Heart icon this is not at the proper place and why so if you go to this border style icon BT and container icon B and container we have height and width of 30 30 with the five and padding four so let's try to set height and width of 30 and width 30 okay we may uh make this smaller 26 and 26 because we have four padding something like this and again this is not in Center it should be in Center uh is it related to frame only this image only no no for the first one the first image left Arrow image this is fine okay so this is not looking good if we do 30 30 then it should look good okay let's bear with this only let's have it 30 only okay so that means this page is also done what happened is API disconnected let me check no it's here okay okay cool so this is page is also done after this let's go all page page page was working fine it was okay from here also we should see the correct design go back and let's work on faes page now this is really matched up first we'll save everything so save all and go to favorities page and this is a collection view with vertical grid layout and the most common way to get height and width for this one we can say we can wrap this in a vertical stack layout okay now this spacing is bad so we have margin 15 and it is working vertically not horizontally uh and if I add padding would it work yes but then it is uh clipped from right side right so this is not what we want let's do this so items layout we are setting it like this so we'll use the detailed version so here we'll say collection view do items layout and here we will say grid items layout first thing orientation vertical then span two so span is if we are uh making our collection view as vertical grid span refers to the number of columns and if orientation was horizontal it should have referred as rows so right now we are using vertical so span two means two columns which is this default then here we can set horizontal item spacing so we'll say 15 and now we should remove this items layout from here and we can see this now let's do the same thing horizontal items and then vertical item spacing again 15 and then we'll remove this margin from border now we don't need that right so we are handling it from the grid items layout only cool so this page is also done we can remove the items yes cool now let's go to profile page here this uh initials these are messed up so let's first save all then go to the profile page here we have these initials so if you have followed me in my previous videos so for label most of the time for iOS we need to add some padding so padding 10 cool it works okay now change password is done my adoptions this page was also fine right that means UI wise design wise everything is fine everything is working on iOS now now the way we expected now let's do this stop it save all and let's try to run it on Android to check if we messed up something or everything still works same so I'm going to run it on Android One More Time Android and we missed the the main page the onboarding page right that UI is also remaining so we'll fix that UI and then login register UI as well okay so for this let's first fix those pages then we'll check uh on Android so let's go to iPhone again okay app is here let's go to profile and log out now go to profile again and go to login page so on login we need to do the same thing for this image so let's go to login register page and here also we have this image so we'll say frame then let's copy all these styling and inside this Frame we need this image and instead of Border Shadow it should be frame Shadow and then stroke can we have border color yes so it is going to be border color stroke will be changed to border color then stroke shape we don't need that we have height and width 250 and the rounded rectangle so we can say Corner radius as 175 stroke thickness 10 so can we set border width or something like that stroke no we don't have it what is it 250 250 Corner radius 175 it should be 175 right let's make this 300 and this one 150 okay so if we set 250 and 250 it should be oh 125 my bad half should be 125 and then is clip to bound through aspect fill all this everything is fine right uh inside frame can we have border yes first let's try to restart the app so that we can see sometime the hot reload does not work the way it should work all right profile login and we can see this something is not right fro I didn't comment out this border okay okay the only thing is Shadow is not working on frame I don't know if I don't use frame I rarely use it because there is that issue which I was talking about I'll show you in a bit but maybe we can try to fix it later there is no point of spending so much time but this is fine this looks fine there's no issue with this okay so we leave it like this only now let's go test. test.com 1 2 3 4 5 6 7 or maybe let's fix the onboarding screen as well so for that what we are going to do we'll go to onboarding screen and we'll do this same same thing we are doing here so let me copy this go to the onboarding screen I think the only difference is this image this is img22 so let me comment this add it and this should be 22 right now here I get 3150 so 300 150 300 and then on this image we had 300 300 height and width and fill everything is fine okay okay save all and now we should be good now let's check on Android it was not working so let me clean the solution uh clean this mobile project cleaning and then I'll run it on Android emulator run it and where is it it is here all right so on Android the UI looks same there is this one uh line I don't know from where it is coming I am not able to fix it if you guys know something about about it do let me know in the comment okay so this is fine this is fine popular pads you may like is fine if you go to all pads let's wait it to load so this screen takes much time on Android than iOS okay this is working the detail page is working go back go to favorities so faes also look same we can remove items go to profile this is fine change password is working cancel my adoptions this is working so everything is working fine now the problem which I was showing you now if I tap on this this image I am tapping but nothing is happening if I tap on this name or price then it opens the detail page but on iOS if if I press on this image it opens up the detail page so that works same for this popular pets if I press on this image nothing is happening and if I press this text then it should open it is not opening from here okay it is opening it was so from image it does not work what has changed it was working before the only thing that changed now we are wrapping our images in inside a frame earlier it was inside border so border this tab gesture recognizes work but on frame it does not work so let's go to home if we go to the top carousal view first we'll work on this carousal view this one so here we have this grid and inside this grid we have our frame image label everything and I have this tab gesture recognize on grid level so if we have frame then the parents gesture recognizer does not work so the workaround would be we can copy this and add this to the frame as well so here we'll say frame do gesture recognizer and then we need to add it like this now if I save it everything should work fine but before that let's do do the same thing for our popular pets and you may like collections so we have this gesture recognizer on vertical stack layout now we'll add this on frame as well so let me copy this and we'll add it on frame level as well so we'll say frame. gesture recognizer and paste it so now save all and restart the app in Android and we again have this error so this error I I am now getting this error quite often so in order to work we need to clean the project then run it again that works it's here let's try now and we can open it go back if you tap on the image it is opening and we tap on the text this is also opening okay so that means this is what working okay that means we are good now let's try one more thing on iOS for the shadow [Music] iPhone frame has that has Shadow right so that might be I don't know what is in global Styles if we look for it frame in this page frame has Shadow Falls border color this is dynamic Corner radius so we are overriding these two and we didn't set hat Shadow to anything so maybe that's why the shadow is not coming uh where is it okay profile log out profile login go to login page login register and on this Frame if we say head Shadow equals true something definitely happened but what I don't know radius 250 brush is this if we remove this okay this is also looking nice now what other properties I can set on this Frame I don't know let's try what other properties we have so we have border color Corner radius head Shadow H that's it h in frame we only have these properties border color Corner radius and head Shadow we are using all these three okay now if we use this thing if I say un commment this and then if radius is zero and the brush if I say transparent transparent or something happen no right I was thinking maybe we can make it uh something like it should have different appearance on iOS and on Android on Android uh we can have the shadow effect and all that okay so let's do this H let's do this let's remove this we have a shadow true so on I iOS let this Frame frame be there and for Android we'll use this border yeah let's do [Music] this so for this what we'll say for this border we'll say is visible on platform we'll say FSE and on Android we'll say true so default false but on Android we want it to be true same thing let's copy this add it on this Frame and we'll say the opposite it should be true oh no no it should be False only but it should be true on iOS like this cool so let's do the same thing on onboarding screen on frame I'll say I true and on this border I'm going to uncomment it and add the same thing on platform false so without any uh platform it is default for all then we are overriding Android on Android it should be true that mean it should be visible and on all other platform it should be hidden that's what we are saying using this let's try it out again I am restarting the app on iOS then we'll check it on Android okay app is here go to profile go to login and we can see this okay now let's stop it and try to run it on Android not again okay let me clean and run okay it's here profile log out profile login and boom so that means that platform specific UI for this section it is also working so we are good now cool so we have fixed complete UI for iOS now next thing is let's start all the functionality is done everything is done now next the signal R so let's Implement signal R so for that I'm going to go back to my Windows machine and there we are going to implement signal r h in API and then signal our client in Mobile okay all right so I'm on my Windows machine now first thing let's close all the tabs close all tabs now first we'll add our Hub signal or Hub in our API project for this in our API project we'll create a new folder we'll call it hubs and here we are going to create one Hub class p hub okay now in order to work with signal R we need to define a derived class from Hub based class so it has two flavors one is normal Hub class and one is generic Hub class so I'm going to use generic one and then we need to provide type t a base class for strongly typed signal or H so I'm going to use strongly type signal R so this type it should be the type which client can connect to this pad Hub or we could say no no no not client can from this p hub the methods we can call from the client this is what it means what what I mean is let's define two interfaces here so I'll say public interface and first I say IAD client Hub in this I'm going to Define methods which are server this from API we can call these methods from our client that is going to be in our Maui side so here we are going to have a method which is let's say pet is being viewed this and we'll get a pet ID for this so from this server whenever we any uh let's say anyone is viewing some pet from this Hub we will notify all other connected clients that this particular Pat being viewed by some user and then the second method we would need that is going to be Pat adopted so whenever some pad has been adopted we will notify we'll broadcast this message to all the connected users that this particular pad has been adopted by someone cool so now this we are going to edit Here and Now what we can do let's have some we can have on connected on on disconnected method I'm not going to use it but I'm just showing that now what we can do so now we can say clients dot all dot now you see Pat adopted Pat is being viewed so we can have this thing these intellisense because we are using this generic strongly typed Hub this generic type of Hub in that case we can have these methods here so we can directly call this okay I'm not going to use it now one approach which I follow to avoid hardcoded method names and to define the actual methods names on this pth Hub I create one more interface where I Define all the methods which this pad have this server side signal are has so I'll say IAD okay it should be IAD Hub client like this and here I'm going to say IAD Hub server here I'm going to define the methods that can be invoked from the client okay so first thing if we start from the beginnings whenever we open Details page P detail page on our mobile app at that time we are going to call one method from our pup server where we'll say I am viewing this pad in pad ID okay then the second method we can say that whenever user is moving away from that particular uh page that detail page then we are releasing the viewing pet right now the user is not is no more viewing that particular Pat so for this we'll have one more let's say release viewing this Pat same we'll have in Pat ID then for adoption we will have int pad adopted int P ID now it might sound confusing because we have this same method here and same method here I'll tell you how the flow is going to work before that we'll do this now I want my padb to implement this interface here I'm going to implement these methods now how all this thing is going to work let me do this when the user from our mobile lab opens the details page at that time we will create a signal R connection okay now pay attention what I'm saying then we are going to create a signal R connection and then we are going to invoke this method from pup server that I am viewing this Pat and from there we'll pass this Pat ID then request will come here on this viewing this pet okay from here what we'll say we'll say await clients do others so others means we will skip this particular client which sent this request so we'll say clients do others all other connected clients will'll say pet is being viewed pet ID okay so when user opens that Details page from there we will have this request viewing this pet it will trigger this to the send this message to the server and from server we will F this message and then we'll notify this message to all other connected users that this particular pet is being viewed by someone else so this flow is fine now when user has is moving away from that page at that time we will say releasing release viewing this pet and then we are going to call this and I I'll tell you why I have this method here what is the point of this I'll show you in a bit but after that what we have if we are on detail page and if user adopted some pack so after adoption user from the mobile client side we are going to raise this message trigger this message send this message to the signal rhub server that I have adopted this path then this request will come to this uh method and now what we'll do we'll do the similar thing we'll say await clients. others do pet adopted now we will notify all other clients that this pad has been adopted by someone cool Sol this is fine now for this release viewing this pad so inside this pad Hub we are going to have a list of uh let's say the currently viewing client uh currently viewing Pats okay so for this what I'm going to do I'm going to have a private static readon I dictionary int which is Pat ID int which is currently uh viewing count we can say and here we can say pads being viewed something like this I cannot think of any other name but this is what I can think of so we'll have this here now what we'll do when we are saying viewing this pad that means some user is viewing this pad so here first thing what we'll do we will check if we have this pet in our dictionary that means someone else is looking at this pet viewing this pet right now so we'll say pets being viewed do try get Value Pat ID and then we'll say out in and currently viewing this is the count and we'll say negation not if this pet ID does not exist in this Pat being viewed uh here H we can set it to zero which is going to default but let's set it then what we'll do we'll say underscore Pats being viewed Pat ID currently viewing Plus+ so how this is going to work if this is the first time we are coming here so currently viewing is zero so we will add this pet to the dictionary with value 0 + 1 that is 1 now let's say two uh users are viewing this Pat already then if the request came to this one we'll check if we have this pet ID in dictionary so it will return true and it will give us the two value which is uh currently VI count two then we'll simply skip this if condition we'll come here and we'll say 2 + 1 which is three that is the current count so this is how it is going to work after that we will notify others notify other users okay and we are going to do opposite of this in this release viewing this pet let's remove this Pro new and here again we'll check the same condition and now what we'll do we will check if this pet is being viewed is true then we are going to decrement this currently viewing because this current user has moved away from this screen that means this current user is not uh viewing this Pat anymore so we can decrease this count now we will check if this currently View is equals z or let's say less than zero if for some use case less than equals to Z that means there is no user who is currently viewing this pad we can directly remove this particular pad from our dictionary there is no point of having it in our dictionary here we'll say remove and this pad Tye okay and if that's not the case that means some user has uh moved away from the this screen but still there are some user who are currently viewing this pad for this we'll do the same thing pets being viewed equals currently viewing this okay after saying this should we do something no we'll simply say return task. completed task because all these methods in a hub must be task must return task right and in this we are not doing any as sync operation so we cannot use await that's why we just we will just return task. from visual this is fine now let's go to pet adopted so for pet adoption we are good we don't need to do anything or should be H H okay we can do one thing if user has adopted this Pat then there is no point of having this in dictionary because we are having this in dictionary so that we can notify users that someone else is looking at this pet and they can adopt it before you so if you the pet is already adopted then there is no point of having the signal connection right so we can say we'll notify others that this pad has been adopted and then we'll simply check if this dictionary has this key which it should if it has this key then we'll remove this from this dictionary like this cool so we are good now okay now one more thing which we'll do now if user is coming for the first time on this screen so right now it will uh raise a request that I am viewing this pet but what if some other user also viewing this current pad so in that case what we are going to do we will override on connected method okay and inside this uh uh we do not have P right uh okay maybe we'll think if we should implement this or not or maybe we should implement or maybe let I can leave it to you so I'll tell you what I'm saying if there are couple of viewers of this current pad if I am the new user or maybe new user in the sense I have just tapped on the pat detail it is opening the pad detail screen and from there I'm going to show I'm going to uh invoke this method sending this request to Signal or server then it will notify others but what if when I joined this this section when I opened this uh pad detail someone else was already looking at this pad so for that case we should notify whenever we are connecting to the signal are at that time we should notify the current user that this current Pat is being viewed so for that what we can say maybe we can create one more method that will be kind of handshake method so okay or maybe we can do this we can have this functionality inside this VI this Pat only huh yeah let's do this inside this viewing this pet we will check if if we have if the that pet has entry in this dictionary already then what we'll do try get value if not if let's say else case here we'll say this pad already exists in the dictionary and what that means is we'll say there are users viewing this P already so in this case notify this current new user that you are not the only one you are not the only one r dispat okay so for this what we can do we say await clients dot how can we callar clients. caller dot Pat is being viewed and here we'll say Pat ID like this okay so here we said that whenever I came to the app if someone else was already viewing this pad then I will be notified that someone else is already looking at this pad cool so I think our pet Hub is ready to be used now we will need this PB client and pup server in mobile app as well so what I'm going to do I'm going to move this to shared folder in here let me move this cut from here paste these here and move these to separate files add it add it I will stop the API okay we have these things here ready now our Hub is ready we just need to add the bre uh using tool now we need to register this in our program.cs this first we'll check if we already have ADD signal r no right signal R dependencies are already installed in this web API project or MVC project we just need to First We'll add Builder do Services dot add signal R signal r am I missing something add signal R add signal R add oh signal I said okay signal R so we have registered signal R now we need to use it so in order to use it we need to Define app do maphub then we'll say we are mapping pad Hub and then we need to define the URL on which this PB is going to be connected so for this we'll sa hubs SL pad Hub like this save everything and we are good Now API side connection everything is done now we need to use this URL in Mobile Maui app as well so let's move move this to our uh app constants okay so here what I say I'll say public [Music] const string and we'll say Hub relative Hub URL or Hub pattern let's call it Hub pattern okay and we'll cut this from here we'll add it here like this and then we are going to use that here so we'll say app constants dot Hub pattern save everything and now for our mobile client signal or client we need to have the complete URL so here we'll say public cons string Hub URL so this is going to be base API URL which is the first section then we'll say slash and then we'll say h pattern so this is the complete Hub URL let's say full Hub URL full URL something like this cool so for AP side everything is done everything is fine now we need to move to client side which is our mobile app so for mobile app first thing we need to install Signal our client package so I'm going to open manage new get packages and here I'm going to say signal R and we'll search for Signal R client so signal Microsoft ASP net core signal. client install apply accept and there is some error what is this error detected package downgrade logging abstraction from 701 to 70 signal our client 7012 which uses Microsoft loging extension 701 701 and what we have Microsoft extension loging dbug let's use 701 only now if we build our mobile app okay first let's try to build API to check if everything is working there okay it build successfully okay this did not get installed do we have 700 version yes so let's better to I Del this thing fine save so I'm going to install the same version which is 7 this version for espit the signal our client let try this one install no not 7012 I want to install 71 install apply I accept cool this gets installed save everything adding an abstract method over oh this is old errors can we remove this no right so let's leave it okay now we have installed signaler dependency in Mobile project now we need to use it so there is only one page where we are going to use our signal arm and that is our Details page Details page we are using a detail view model which is this one so we are going to use this let's close all other tabs so close all but this fine okay let me minimize the collapse everything great nowm so we how we are getting that this is the on pad ID changing this is the first thing which gets called when we are opening our Pat Details page right so we need to configure our signal our client here only after the Sur task. 100 I'll configure my signaler client signaler connection so for this let's do this create a helper method so I'll say private async task and we'll say let's say configure say signal or Hub connection his Sy something like this fully detail okay and inside this I'm going to use try catch first thing and try catch exception VX okay inside this try first we'll create our connection so we'll say word Hub connection connection equals we'll use Hub connection Builder new Hub connection Builder and using this Builder we can configure our hub first thing we'll say with URL and here we have our app constants app Conant dot how full U okay then do build now our Hub connection is ready on this Hub connection we are going to Define couple of things the methods which this subub connection can uh receive from the server okay so from server if you go to our Pat hub from p hub p Hub so uh these things when we say clients. others Pat adopted this one and then inside this nothing is happening then this client. callar Pat is being viewed clients. others Pat is being viewed all these these calls so these are coming from IAD up client that means we need to Define these two things in here so for this we can Define on okay and we can make it generic and this is the type of parameter we are going to receive and we are going to receive Pat ID as a parameter and the type of that is going to be int which is Pat ID so int and then name of the method from there we are going to call these methods right so we need to Define these so I'll say name of IAD Hub client dot now we can Define both of these so pet is being viewed first I'm going to Define this then we have action delegate here we'll say a sync we will need a sync right let's see so here we are going to get Pat ID and now we will check we have one situation here we are going to call it from here and at this this point we don't have this pet ID we have this pet ID so let's get this pet ID as a parameter so we'll say in current pet ID we'll call it like this so here we will check if current pet ID equals equals this pet ID then only we need to show this show some message okay now the point here is point of this condition is we will always uh notify for all the PS but maybe this time this P this current user is not viewing this particular uh pet so let's say I was viewing pet ID 1 you were viewing pet ID 2 and there is some other user who starts viewing pet ID 3 if he just opens that pet ID 3 so I and you should not be notified for that because I viewing P ID 1 you are viewing P ID 2 we are not viewing pet ID 3 but that message will come here as well so it will come here and now we'll check if we are not viewing that P ID then we will not display anything to the user cool so here we need to notify the user that something has happened so for that we'll say show toast Miss sync and inside this we will display our message we'll say someone else is also viewing this Pat something like this okay now this is going to be awaited so we'll add a s here now there is one issue here so this thing this does not gets invoked on the main thread because this is a kind of async operation which keeps on running in background so from here we need to somehow send this message to the main thread main UI that something has happened like this for this doed Maui gives us something and that something is dispatcher so we have app or application dot current dot dispatcher we have this object so on this dispatcher we have a method dispatch async we can call this method to send something from any other thread to the menu it so here we'll say just invoke this message without a wait like this like this and then we'll add a weight to this main thing okay remove this we'll say a wait and we'll remove the second line now we don't need this cool so this thing is done now we have one more method which is let's let me copy this that method is p adopted right so pet ID if current pet ID is that pet ID then we'll do this and what we are going to do here and now we have one more is no no we don't have that issue okay now what we'll do on this Pat details so we'll access our Pat details object on this we will uh use this adoption status and here we'll say adoption status do adopted that this pad has been adopted by someone and then we'll notify we'll show this toast so we will show this message which will say someone adopted this pet you won't be able to adopt this P now you won't be able to adopt this right now like this and now we are good with this setup okay now we have set up after this we will start our Hub connection right now this is not started here we are just configuring our Hub connection now we'll say Hub connection do start Isn like this and this is going to be awaited now our connection has started after starting it we will notify the P we'll simply invoke this method viewing this pad now we'll say that our connection has established now we'll say that I am viewing this pad so you should notify all other connected users that I'm viewing this pad so now we will invoke that method here for this we'll say await H connection dot send async name of the method which is on server side we'll say name of IAD Hub server dot viewing this pet I am viewing this pet which pet the pet ID which we have as current pet ID like this now everything is set up correct now inside this sketch if something from this section does not work then we are good we can without this exception because this is not an essential feature this is not an essential feature for this app if there is some issue with the signaler if there is some issue with the signal or our connection we can skip it as the app will work without signal l t will work fine without signal r as well fine without signal as well okay so we are good you might uh add this exception and maybe you can check this exception or maybe log send to some logging service and then you can maybe troubleshoot it if you want but in our case in this particular app we can simply skip this exception now we have created this subub connection we have started it now when we will move away from this screen we should stop this connection we should not leak this connection for a very long time if we are not using it right so we need to stop it in order to to stop it we need to have access to this Hub connection but this is a local variable for this method so what we'll do we will move this variable out of this method so it will be a class label variable so this build returns Hub connection so that is this is going to be a hub connection here we'll say private Hub connection this is going to be in the label and we'll say Hub connection like this and now we are going to change this Hub connection to this Hub connection and we'll remove this water like this cool we have set up our signal our connection now we are going to call it from this pad details on this on pad ID changing so we'll say configure signal R and we'll provide this Patti with up cool okay fine now after this as I said we need to uh release this connection so for this we need to know that when we are disposing this when we are moving away from this we will dispose this so we can say I disposable and then we can simply Implement our interface or maybe let's use I sync disposable I sync disposable we'll implement the interface in here so what we'll do we'll first check if H connection is not null then we'll say h connection dot stoping like this this should be missing in this case okay so we are good now H but before doing this be before stopping we should say we should release this part this current pet right we should release this so we'll say a wait Hub connection do send async and here we'll say name of IAD hub server dot release viewing this pet and then pet ID like this and then we'll stop it let's add try catch block here as well and from here as well we can skip this exception skip this exception cool now we are good now there is this adopt now is sync method we have adoption here we have setting it after setting the adoption status before moving to go to async Method let's notify other users so we'll say await and it's always a good idea to check if a connection is not null okay then we'll add try catch again where we'll say have connection do send async name of iub server. Pat adopted and then Pat ID so this Pat has been adopted like this like this cool so we are good with this setup now the only thing is this dispose on this details view model we don't know when this dispose method is going to be called so whenever we are moving away from this screen we should manually dispose it what I mean is we will go to our page Details page it's code behind Okay and here we'll do this we'll override one method which is on disappearing that means when we are moving away from this uh this page at that time we would explicitly call dispos sync method like this or instead of calling dispos a sync what we can do let's go to details view model and let's cut this logic create a new method here so we'll say public asnc task and we'll say stop H connection like this like this and from disposing we will call this stop hub connection and from this on DC disappearing we'll say view model dot stop hub connection like this this should be see and for a safer side we can maybe Implement ising disposable on this Details page as well this is coming not interface okay we'll implement this and we'll call this same method from here as well like this now complete setup is done now we can try it out so in order to try it we need to have two devices okay so first let's try to see it on this uh first let's try if we are able to run our mobile app without any issue so let's first run the API so we'll say start with debugging okay API is running now let's run our mobile app so mobile exela all right app is running that means let's open the detail page first and I think we are good maybe we can try try adding a break point so that we know that what is happening stop hub connection and then let's use this configure Hub connection like this and let's use this thing as well Hub connection Hub connection like this I'll go back stop up connection gets called we came here and we have some exception here we need to check what exception we are getting let's use let's have that here as well just for debugging purpose so let's add this breako here as well let's run what are we missing configure Hub connection Hub connection Builder H connection this start a sync we have some exception and that exception is response status code does not indicate success 404 not found and why so what is the full URL fully Ur is this one with double slash this is the issue double slash it should be single slash only so let's go to our app constants base API URL in H pattern we have this for uh just remove this save and now we need to stop the API save everything let's run the API again and then I'm going to start now app okay app is coming let's open the detail page we are here start a sync started we send a message Continue and we are good let's move away from this spage stop hub connection we'll came here send aing and then stop aing so that means we are releasing signal or connection and creating signal or connection just fine cool now what I am going to do let me try to connect my physical device my mobile device and I'm going to show that using viser so we'll see that this thing this uh this notification toast messages are working so let me connect my device install the app on my device I have connected my device and I just hit I'm running the app so it is going to take some time because it is going to install it for the first time in my mobile device so let's wait for it installed it is checking for why is says okay now I can open it loading and we can [Music] see okay this is working this is working this this is working go to all pads okay we have a list we can tap on some pad and it should open the detail page oh we have this breakpoint got hit let me disable all the break points disable continue we have detail page and we have this data here you need to be logged in and it crashed okay so let's do this I will run this app directly without debugging on my mobile device and let me open this so I'm going to open apps on both these emulator and my device side by side okay so let me do this what is happening so let me open buddy here on my physical device and I'm going to open it on this device the Android emulator someone else is also viewing this pet this thing is here we got that notification on both of these uh devices now if we go back if I open this whiskers I should not see any notification here right now if I go back and open this pad from my physical device whiskers now I should see the notification on both of these devices right someone else is also viewing this pad cool now let's find some pad which is not adopted Kumar is this adopted no Kumar is not adopted I'm going to open it from this left screen as well so let's adopt it from somewhere from this device I'm not logged in let me log in on my physical device right so I'll say okay if I'm saying no I'm getting this 401 that means there is some issue issue is even after saying no it is sending that request but it shouldn't we'll fix it but first let's check the functionality I am login page so I'll simply use the same credential test. test.com and then password login we are here let me open Kumar again I should see the notification on both the screens I did not get it on my left screen okay we'll check this as well now if I adopt it from my physical device I'm going to adopt it so keep an eye on this emulator I should see that notification here that someone else has adopted this pad and this adopt Now button should become adopted and disabled on both the devices adopted someone adopted this pad and now this is adopted that means all the functionality is working signal R is working fine in this case okay now let's see that issue it was adopt now it should be in adopt now is saying when we said not logged in not logged and from here if we said yes then it come here and if we said no okay if we said no then it should break from here but that is not happening so for this we need to use this in a different if so if this then we'll check if this return always from here right no no not always yes we are going to return always from here so if user selected this yes user wants to login then it will go to login register page and it will not execute further code it will return from here and if user selected no user do not want to does not want to login then also we'll know not uh navigate user anywhere but we'll directly return from here we will not execute this logic so this is the only missing piece that we done already so looks like everything is working what I demoed you all that thing is working everything is working fine now so we are done with this app that's all what we are going to do in this app so please like this video share this video subscribe my channel and do let me know in the comment if you like this video and if you want me to create this kind of complete F stack apps which includes all these features mobile Maui API connection and all these things signal R all these things if you want me to create a others videos like this please drop a comment share this video for sure and like this video and if I'm going to get a better uh visibility and if this V video has views it will encourage me to create other videos as well okay okay so I think that's all I will be back soon with some other cool project till then bye-bye
Info
Channel: Abhay Prince
Views: 5,391
Rating: undefined out of 5
Keywords:
Id: 1js5U3gWamg
Channel Id: undefined
Length: 665min 0sec (39900 seconds)
Published: Sat Oct 14 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.