Playlist Builder - Part 1 , Building a .NET MAUI app from scratch

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
foreign [Music] Series in this series I will build a net malware app from scratch and in this series I will build an app based on the Spotify apis and the reason for that is that I wanted to have good real data to work with so this will be more like a real world scenario so my idea is to build an app called playlist Builder where we can search for artist albums songs and we can create playlists so let's get started and set up the project and build the first part that I planned to be to acquire the token from Spotify that we can use for accessing their apis so what I don't was show in this is when I went to the Spotify developer dashboard and registered my account and my app but that was pretty straightforward so you can go to developer.spotify.com and do that yourself if you want to build something with the Spotify apis so let's get started in open Visual Studio so here I have created a new project I have used the default template uh called dotnet Maui blank app so here we have the project called playlist Builder and we will start to create what we need for setting this up so let's start and create the first views and for that we need to have a views folder and a view models folder so let's create them juice view models and we can remove the main page because we don't really need that one and if we want the main page we will call it main view because I will use the nvvm pattern so delete that one and we create a new view and we call it login view because that is what we will do today login and we create a view model login view model and then I want to use the file scope namespace because I think that makes the classes more clean and now we need to implement property change because that's something that you need in MVM so there are multiple ways to do that you can do it yourself you can use the community toolkit.vm and that is what we will do today but we will also use my own helper library that is called tiny MVM and that has a dependency on the community toolkit anyway so let's go and install the tiny mm package so we open the nuget package manager we search for tiny mvvm and here it's important that we use the Maui package that is called tinyambam.m.maui seems like I have to add a package description here but let's install that okay MVM has a view model Base Class that is called tiny view model but often in many products we want to add things to base view models so we will add one in between so let's go and create that one so we call it view model and this one can have a tiny view model as space class using dynamvm fix the namespace here too and now we want to have Global uses because I said I want to have the Clauses and the files clean so let's remove this one and we can instead add them in the malware program file for example but we can also add this in whatever file you prefer so let's add them here we can make all usings Global here so and now we don't need to have the using for tiny MBM here and we can make this class apps direct because we don't want to initialize this one okay so now we have the login view model we have the login view now we can go to the ioc container and register both of them because if we want to use them with ioc and we want for example app shell to create them with ioc we need to register them both the view and the view model you will see more of this soon so Services dot add transient it means that it will get a new instance every time we ask for it so main name of main view we remove that one log in view and builder.services.ad transient login view model and now that was a few more usings added here so let's do them Global too so and now we can go to the login View and we remove content page as the base Clause because we want to use tiny view but we will specify that in the saml so let's remove it for now and now we can inject the login view model here view model just like that we add the field because I want to use that one later and now we set binding context context to login view model just like that so okay let's go to The View so now we need to import namespace for 10 mm like this tiny and Vamp Maui and now we can use the base view model and I'm them colon tiny View and this is important for some of the features that you can use with tiny MV and them that you will see later in this series so title let's change that to login and to make the Bindings that we'll use compiled we use x colon data type and set it to the view model and that means that we need to import The View model namespace so let's do that [Music] um View mode drills let's see if you have intellisense yes we have so let's say VM Dot login view model okay now we're done with that so now we can start to add some content here so because we want to log into Spotify we need to use their way to login and that means that we need to have a web view because we cannot use the apis to log in and that is a good thing because we don't want the users to imp put there credentials in our app and then post them to uh Spotify okay for us developers that would be more simple but from a user's perspective it's more secure if they add the credentials directly to Spotify so that's why we will open embed view inside of our app and use Spotify login web okay but first let's create an image and a button that says login that will trigger the opening of the webview so I have prepared with some images but we need to add them to the project so we go to resources images and then we go to add X isting files I will add this singer to the project we copied the directory we go and make sure the build action is malware image okay now we can use that and for this page I will use a grid as the base layout because I want to have uh controls in different layers and the grid is good in that case because you can have multiple shines with grid and they can be on top of each other's so we remove the label we add the image image source is singer dot AP yeah and we set aspect aspect fill because we want to have the aspect but we want to feel the comp the whole page so now we can add the button here so button text login to Spotify and we want to have it in the middle of the page a vertical options Center horizontal options Center okay and now we also need a command so that we can handle what should happen when we press the button so let's go to the login view model and now we're using community toolkit.nm that has Source generators I have done a video only about that let you go and check out if you want to but to be able to use Source generators we need to make the Clause part show so let's do that and now we need to create a command and with Source generators with Community toolkit we can just say that a method should be a relay command private void open login and this will generate a command property that is called open login command when we add the attribute so let's add attribute We Lay command open login add a method body like this and then we have can add a property that is called show login that we can use in the view to open up the webview so let's create that property and we'll do that with Source generators through so private Bool show log in it's important that this first letter is lowercase because the property name generated by the sources generated will be with uppercase so keep it with um so then we go and add the observable property attribute and now uh here we have an error because we don't have a base class that is an observable object but that's because we don't have added our view model as the base class so we do that so and the error is gone so now we can see that we have a property generated because if we write show here we'll get a suggestion to use the property and we should always set the property if we set the field it will not trigger properly changed so show login is true so now we can go to the view and we can say command binding and open login command and now we will also get intellisense and the reason for that is that we set data type to login view model if we don't do that the binds will not be compiled I will not get intellisense and we can also go and add those usings AS Global uses because we will use them on more places and now we've got some errors because we removed usings but that will be fixed by adding them here and I prefer to group this juicing a bit so for example we can have the usings that is for this project together we can have all usings for two Community tools to add them together and all using first time in them together because that would be a more structural way and find them okay so so now we can try to run this app to see if this view works but to do that we need to go to the Shell and update that because here we have a main pitch and we remove main page so let's change that so local is the namespace of the root of the project so we need to change that so we can call it views instead and playlist Builder Dot views and Views Dot login View should be our first view that are loaded and we can should not have home as titles let's say login instead log in and Route should be login page okay let's see if we can run this or if we have some other errors that we need to handle first so we can try to run it on iPhone 14. okay so here we have the app and what I think here is we don't need this navigation bar here because we want the image to fill it up and I think we should style the button a bit so let's do that so first we go to the login View and here we can set shell Dot show Dot nav bar is visible so that false let's see if our tree load works today too yes it did so now that is gone and now we have some wide area here because but that is because of safe area we can remove that later so let's go to the Styles folder and here we can see that we have a lot of colors set up but I don't really like the way they have named the colors because they have the colors in the name I prefer to have it like primary is okay because I have a primary color then with a secondary but then we have a white and black and primary brush is okay in Gray 100 brush no we should remove this and name them better because we don't want to have the color names in the uh the in the key of the color because if we want to change color that will be weird and then and that means that we need to change them everywhere so let's remove the colors and create new one so we can call this primary color that is pretty okay but I think accent color is a better way because then we can have an accent text color that matches this color for text if we have and primary and we have a primary color that is not maybe the primary color we use everywhere in the app because that will be something that would be good for body text this can be like everywhere where we used accent color and that will probably be used on bottles and stuff like that so we create um accent text caller 2 and that one can be white like that and when I'm working with colors and I'm not a good designer that knows good colors that fit together but there are good tools for that for example we can go to colors.adope.com and use the color wheel so if we have one accent color that we want to use we can just enter that one in here so let's take this one for example we add it here and we will have a lot of colors that fit good together or we can go and explore and they can help us with color palettes so I already found one that I liked so let's go and take that color and that one is is this green color it's not Spotify green but I think it's a nice weight I have a green color because Spotify is green but it's not exactly the same that makes our app a bit unique anyway but it doesn't really matter because we'll not publish this app to the App Stores but yeah it's fun to make something looking good so styles here we have some default Styles specified by Microsoft yeah and they are pretty good but they're using this gray 950 and stuff like that everywhere so let's go and remove them and start over with styles so let's create a style for the button so Style Target type button and here if we want to add this style you have two specific buttons we can add a key to it but here I want them to be on all the buttons so then we can add a Setter property background color value and here we use the accent color static resource accent color and we also add a Setter for the text color value static resource accent text color just like that and now we can restart the app and see how it looks Now Yep looks better and more unique than the default colors okay so let's go and add the web view to the login page and my ID is we will add that and when we press the button it will animate it up so in the grid we create a webview is visible so that one to false and then we will change that to visible when the button is clicked but we also want to give it name that we can use from the code behind foreign so we call it login web like that so and we also want to wrap this in a frame and the reason for that is we want some round nice corners on top of it so let's do that and we can give that one a name too so we can use that also from the code behind let's call that login that is visible to force that we don't need that there we can have it on the frame instead false Corner radius 10. border color let's set that one to Black we should put that in a style later and then we don't want any padding right now and this one has a default padding of around 20 I think so okay now we are done with the UI we can make it the code a bit nicer so now we can go to the code behind so when we have this property changed in the view model then we want to run some animation code and that animation code I prefer to have in the code behind so we need to wire us up to the property changed event so let's do that and we should do that in the on a pairing method and in the on disappearing method we should unsubscribe to them and so login viewmodel dot properties changed plus is equal to and create a method to that but we put that method in the end like that and then we should honest subscribe when we leave the page just like that so and now we are ready to write some animation code here so let's go and do that so now we have a properly changed handle method so let's check that this is the property that we want to use so either proper name is equal to login view no it's equal is equal to name of I always use name of wherever I can because it's better than hard coding strings because you will get an error if you write something wrong so login viewmodel Dot show login that so first we need to set um source to the webview and that Source should be like this with a client IDs and redirect URLs and some states for Spotify so let's go and create that constant class because we should break things like this out to a constant class or another class because we maybe want to reuse them on other places in the app so constants make this file scope here too we make the class static because we don't need in just this so so then we add the constants so a client e the incline secret that we got from the Spotify developer dashboard don't worry I will regenerate this secret before I publish the video and redirect URL it doesn't really matter what you put here but we need to have one so we can be able to detect when the webview or navigate into it but you will see that soon so we can go back here to login view Sam all the TS and now we don't have any errors and we have The Source set so now it's time to start the actual animation so let's say login translation is equal to height because we want to hide this view first so we can animate it up and when we have done that we can set it to visible because it will not be visible anyway because it's below the screen so and now we can do a translation so login dot Translate to and that required another namespace so we add that one to the global usings 2. like that okay translate to and then we will have then we will add an x value and an e value so X will be the same so we just use login.x and then we will set 100 here as the I value and that because we don't want it to go and cover the whole page we will have 100 pixels in the top left and then we can set an easy to easing.bounds in bounce out cubic in I prefer linear but you have other options if you prefer that okay now we can go and see if this works so let's start the iPhone simulator again oh what I forgot here is to set this date field the state is just something that we can set if we want to so we can see when we get a callback that we have the same state string as we sent to the login page that's just the security thing so we can add a private read-only field that we can use here so we can use the same state for the whole life cycle of this View and we can just use the grid newgrid.23 just like that so now we have the State field and now we maybe are able to run the simulator so let's try and press the login to Spotify button yeah and now we have it opened here so now we can continue here to for example with Google because I created my Spotify account with Google oops we're not authorized to do this because of the an invalid user again or this L this allowed user agent and the reason for that is that the webview will not have a user agent by default and right now we cannot easily add that to the webview but I have seen their own pull requests in the.net mauic repository that will add a property called user agent here but one good thing with that is that I get a chance to show you who handlers works so we can add them for example at the top of the file in the Constructor so we add Microsoft dot Maui Dot handlers Dot webviewhandler then Dot mapper because Handler is something that Maps malware controls to the native control and we want to append the mapping we will give the mapping key can be more or less whatever we want but say user agent and then we have an action post into here so Handler web View let's add that to new line and here we can add the actual content so for Android we won't access the Android native webview so we add an if with conditional compiles so we compile this different on between IOS and Android so and if so now we can see that we have.net 7 Android as Target project so let's start with that so then we can say Handler dot platform View and here we can see that we accessed the Android web kit that is webview control and that one has a settings property that thing is property and for that one we can set user agent string and here we can set that one so let's create a variable so we can reuse it and here I tried with different options I tried the default one for Chrome for example but that did not work then I got an other error once I draw in Spotify but if I just wrote Chrome here like this it worked so let's go with that user agent and for iOS we will do a similar thing so let's say it doesn't sell iOS up there and we can get intellisense for that instead so we set platform View and custom user agent is user agent so now we have added this to all our web views and we can try again and run that so log into Spotify here we have it continue with Google I will add my credentials so now I have entered my credentials and the only thing we need to do is to accept that that this app can log into Spotify so let's press exit there but nothing happens and that because we are not listening to the navigation of the webview yet so let's go and add that so we can add that one here too so we can subscribe to it on appearing and unsubscribe in on disappearing and so log in web Dot navigating we don't want to have navigated because we want this to happen directly something changed so navigating Plus create a method for that one we move that to the end of the file and then we unsubscribe from the event here just like that so what we need to do now is to listen to our webview and detect if we have the redirect URL in it so let's add an if statement to check that just like this if this not contains redirect URI in the string and it contains this actual value of the redirect Theory and the reason I add this is because we don't want it to catch this the first time when we set this when we set this URL containing the redirect Theory so we will only run this code in the correct step of the authorization so now we should parse that query string to get a code from Spotify and I prepared that code because that is pretty boring to look on when I'm writing so now we have a code and we have a return State and now we can check that this state matches what we sent to Spotify so we can do that if return state is equal to state and we got a value in the code because this code is something that we will use to get an access token that we can use for the API so is null or white space is not null or white space so like that and now we can animate this login view away login the Translate to X is still the same so login dot X but here we set this to height again as we did in the beginning here so then we set easing should be easing Dot linear here too and we can set login dot is visible to force after that this has completed and that also means that we should have an await here because otherwise this will happen directly so let's add the async keyword there so and now we need to handle this code and that is something that we should do in a service that we will call from The View model so let's go and create a Spotify service add new class I support E5 sir this because it's good to have interfaces for everything to make things more testable even if we will not write any test in this episode interface and here we can add a method return the task of bull so if it succeeds we return true otherwise false we can call it initialize initialize the Spotify services for us now and then we put string uh Alf code here and outcode is the code that we get back from the login parts so we should of course put that in a separate folder because that makes things more nice services and more structured I should say so and then we can align the namespace with that two so and now we go and create the actual implementation so defy sir this Implement I Spotify service interface remove this throw exception stuff and now when we do this we should call the Spotify API with a basic authentication header so we first need to generate the value for that and that will be base 64 string based off Spotify client ID and client Secret and we will do that like this so encoding that you'd have Auto get bytes and pause the string Spotify client call on Spotify client Secret and convert to basic four string and post bytes there so now we have that now we need an HTTP client with that header so create that one client is new one later we maybe want to reuse the HTTP client but not in this case because this is the only time we have this header and they also want the content to be form form encoded so we create that content like this formula encoded content and we have a key value pair here so we have the auth code we have the redirect Theory and the grant type and that is authorization code that means the code that we got from them so now we can post that to Spotify and we do that like this client dot post I think and put the URL account spotify.com API token so and we need an async keyword up there so and now we should have response that hopefully are successful but we will check that so we need we will get Json back so from the response we read the content and even if this is not successful it's always good to read the content because in a debug scenario this is good to check if there are some message in the content property that tells also why things went wrong so then we have Json then we need to deserialize it and then for that we need a model so let's go and create a models folder those and we created auth result class auth result like that and this one can be a record and it should have two properties access token and refresh token and that is something that we can use to access the apis and refresh token is something that we will use to get the new access token when the access token not are valid anymore so now we have that one we can go back to the service and we can deserialize it and we put that in a result variable so we use Json serializer and the deserialize method say that we want to be auth result then we put the Json to it and now we can create a field for this service that is access token and that means that we can use save it here so long that this class is alive in a later episode we may be will save it to the secure storage so access token is equal to result dot access token and then we return response Dot is success status code so now we have completed the service and now we want to register to The ioc Container so we can inject it into our view model so let's do that Builder dot Services dot add Singleton because we want that one to live the whole lifetime of the application so I bought the file service and should map that to Spotify service and I want to say map I mean that when we ask for I spot device service it will solve it to a Spotify service clause so and then we have a use things here for that added so we make that one Global too so we don't need to add a new using in the view model so let's go to the view model and we can inject a Spotify service here and add it to a field that I don't want to have there I want to have it in the top above the Constructor so this is usually how I structure my view models private fields on top and not all diode Fields because those one that are generated by The Source generator I will have below the construction because I see them more like properties but after the phase we have the Constructor and properties and then commands and after that I have other methods if I added some for example we need to do that now because we want a method to handle the auth code that we can call from the code behind so public async task handle off code the ring out code and now we can call the Spotify service wait spot device service Dot initialize how code so the last thing we need to do now is to go to the code behind here and we call that method and pass the code variable so we don't want the view to wait for that so we add a task Dot run to run that asynchronously and we will add async there then we can do a weight login viewmodel dot handle alph code and parts code and now we have a warning here but we can fix that easily but add this card like this okay now we are ready to run this and see if we can get an access code to Spotify apis so let's set the breakpoint here in the Spotify service so that for example and then we go and run that so we press the login to Spotify button and now it remembers my credentials in the browser so the only thing I need to do is to press accept here and this is Swedish for accept so we can go inside the breakpoint here two to see that we will go in there so except so we need to do some scrolling that to make that work so and now we can debug this and we can see the URL is this long one with our redirect URL here and a code in the query strings that we can use so we step this through or let's see if we have the same state b4e start with before E both of them so they are probably the same so okay let's let the debugger go yeah now we are here so we are ready to do our post to the API so let's step forward you got Jason back we got an access token here and we have a successful status code that's great and it also closed the webview so what we have done today is that we have started to build a Spotify playlist the Builder and we have added a login View and we have retrieved an access token for the API that we can use in the coming episode and I think this is a perfect place to end the first episode so if you like this and want to see more of it please like the video and subscribe to my channel because I will create more episodes when I continue to build this app and I will also create other type of videos where I build.net and Mouse stuff so see you next time bye bye
Info
Channel: Daniel Hindrikes
Views: 4,648
Rating: undefined out of 5
Keywords: spotify, dotnetmaui, dotnet, .NET, .NET MAUI, cross-platform development, cross-platform, app development, ios, android, visual studio, code tutorial
Id: s8sQHZ4845k
Channel Id: undefined
Length: 49min 1sec (2941 seconds)
Published: Fri Feb 03 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.