Build a Complete Android App with Firebase - Full Course with Kotlin

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
we're going to build an app which allows you to update your status using only emoji and you can see the emoji status of everyone else using the app we'll be wiring up several core firebase components including authentication cloud functions and firestore so you can take what you learn here and apply it to pretty much anything else that you're building [Music] the app we're building in this series i think is really cute it's called emoji status and it combines a bunch of really important firebase services in a nice package the idea of the app is that we can use emoji to broadcast a status or a story emojis are unicode characters and they've become really popular as a means of communication in the past few years because more and more phones are able to render them properly in this video i'll go through the app in a bit more detail i'll talk about the architecture and then we'll actually start coding in the next video i'm also planning on publishing this app which is super exciting and so i'll leave a link for that when it gets approved in the description right below the like button i have the app running here in the emulator and the only way that we allow the user to create an account or sign into their account on emoji status is through google and because i've already previously authenticated via google i'm able to hit that button automatically go into the main screen of our application and in fact we only really have the login screen and main screen so this is pretty much all there is and i've signed in as myself rahul pandey and what you're seeing here is my status my most recent updated status along with the most recent status for every other user in the app and what you can look in up here in the menu is i can log out or i can actually update my status so let's say i want to update it to i'm playing uh you know basketball and i'm not doing so hot so i'm crying about it tap okay and then that update gets sent immediately to firestore which gets shown in our recycler view over here the other cool thing about this is that as soon as anyone in the app updates their status that will also be immediately reflected in our app for example my friend branner branner bispus he's actually been making some banana bread and so let's say that he updates his status and right away as soon as he published it it got updated on our end in the emulator here we're going to build exactly this the published version of the app has a few extra features which i'm happy to walk through if people are interested but the only other thing i want to do in this video is walk through the architecture and how the pieces fit together like i mentioned in the intro there are three firebase services that we'll use to power our emoji status app first is firebase authentication for signing and sending out of our app next is firebase cloud functions which allows us to execute code on a server some javascript code on the server whenever an event happens in our app and then third is cloud firestore which is essentially the database for our app and so hopefully in the next few minutes you'll see how these different pieces fit together the first is firebase authentication users need an identity in your app basically any meaningful app is going to want to associate the data that the user creates in the app to some sort of server or some data in the cloud just so that if i wipe the data on my phone or if i get a new phone and when i sign into the app i expect my experience to be similar to what it was before and so for that you need to have some way of creating a unique identity for your user there are three broad options for logging in at least as presented from the firebase authentication tool one is you can allow the user to sign up by email and password second you can use a federated identity provider for example google facebook twitter github etc or third you can use phone number sign up and we're gonna be talking about the federated identity provider and in particular we're going to be allowing users to sign into the app using google and the reason i prefer this method is because with email password no one wants to remember another password right so typically if you already are signed into google or facebook it's the easiest way to get people into your app and the second thing is that the use of google sign-in or facebook sign-in allows us to bootstrap the user profile we get information about the user that we probably wouldn't have gotten with the phone number sign up approach or email password sign up approach and in particular what i'm talking about is the display name of the user and the photo url of the user so a profile picture and that kind of makes your app feel more complete so one of the annoying things about firebase authentication is that once you sign in to the app once you create an account in the app that user entity that's created has a fixed set of properties such as the email name and photo however if you want to store anything else about the user for example in our app we want to store the string of emoji representing that user status or maybe you could imagine we want to store the updated time of that status or any number of other things that is your responsibility you have to store other properties on your own and that's where cloud firestore comes in cloud firestore is going to be the database which keeps track of the user along with their status there's one more annoyance about firebase authentication which is that the currently signed in user can only get information about themselves but if you think back to the main screen of our application we want to be able to query for all the other users in our application and so in order to do that we again have to now every time a user is created in our app we have to create a user document or a user entry in our database in firestore and store the data for that user so here's what this will look like we're going to have firestore we're going to have a collection called users and inside of the user's collection are various documents each document represents one user for example here is brainer bispus my friend and they have a certain status which is represented by that field called emojis and so this is where firebase cloud functions comes in as soon as firebase authentication tells us that a new user has been created then we want to trigger a cloud function to run to automatically add another document to the user collection so in general cloud functions allow us to run code when certain events are triggered and so in our application we're going to be running some javascript code when the user account is created and that is what is going to be adding to the user's collection with some default emoji status which the user can then update so hopefully now this architecture diagram makes more sense we have firebase authentication which is in charge of signing and signing out and whenever a new account is created that's going to trigger a message to firebase cloud functions and firebase cloud functions is then going to create a new user document which will be put inside of cloud firestore and that will get sent down to our client our android app which is where it's going to be shown in the recycler view and if i click on that edit icon that pencil icon in the menu and i update my status that will send a message up to firestore to say hey i want to update my emoji status and send that out to all the other clients as well so even though there's actually a few moving pieces here the whole app is less than 200 lines of code um and the way i want to build this out with you is first in the next video we're going to be building the login flow then we're going to create a new user document with a cloud function so whenever the user signs up we're going to create a new user document then we're going to implement that list of users in a recycler view and we're going to query from firestore to get that data then we're going to be allowing the user to update their status using that edit icon and finally we're going to restrict the entry of what you can put in that edit text to only be emoji one thing worth mentioning is that i'm really focusing this series on how does an android app interact with all these different firebase services so the reason the app is less than 200 lines of code is i'm writing almost all the logic in the single file main activity.kotlin if you really wanted to publish this to the play store i would recommend breaking things apart into different files or different classes just to keep the app more maintainable i also would recommend that you have some familiarity with android you don't need it but it would definitely help for understanding if you have done a little bit of android programming before if you have any questions or feedback as you go through it i would love to connect with you i'm at rponde1234 on twitter youtube and linkedin and finally i wanted to just mention a big thank you to free code camp there's a huge transformation in the world of education going on right now and i think it's pretty awesome that all of you are able to learn so much valuable content through free code camp and i'm really happy to be part of that as well the goal for this video is to allow the user to create a new account or sign in to their existing account using google sign-in with firebase authentication and once they've signed in they should navigate to a new screen which is the main activity and on that screen they have a menu option to log out so what i have here is essentially just a new project i call the emoji status app and there are only two activities so the only thing i really did after creating the empty project template is i added one more activity called login activity and login activity is the one where i added these intent filters so when you start the app the first thing that we're seeing in the emulator here is the login activity and our goal now is to integrate firebase authentication and add a button so that when they hit that button and successfully authenticate they'll navigate to this main activity which is for now just an empty activity the first thing we'll do is create a new firebase project for our application so go to console.firebase.google.com and hit this add project button i'll call this the same as what i called my project which is emoji status app hit continue let's disable analytics for now just because we don't really care about it and then create project and this will take a minute or two to finish all right so once it's set up hit continue and we're going to get started with the android version of this so the app package name is something that you set up when you were creating your project so for me it's it's this edu stanford arcade honda followed by the app name i'll leave the app nickname blank and what you need here is a debug signing certificate sha1 and this is needed because we're going to be using google sign in so if you hit this link then you'll actually see how you can do it based on your platform i'm on a mac so what i'm going to do i'm going to copy this so i have the terminal open over here so i'm going to copy that hit enter and the default keystore password is just android and then here you can actually see print out the different certificate fingerprints the one we care about is the sha one so i'll copy that now go back to the setup and paste that in here now we can register app and then what this is going to do is it's going to create the project for us and put all of the information we need to associate our android app to firebase in this googleservices.json so download that and then in android studio open up the project window the project tool window and we want to drag the google googleservices.json into the app directory so i have over here i'm going to drag this into app and i have a confirmation dialog hit enter that's good let's go back here and hit next all right so in order to add the firebase software development kit sdk there are a few modifications we need to make both at the project level build.gradle file along with the app level build.gradle file so in the project level the only one that i found that i need to add is this one class path copy that now let's open up android studio and instead of create all scripts remember there are two build up gradles we're going to be modifying initially the one the project level and we're going to be adding this line for the class path google services now we go back and at the app level build our griddle file we're gonna we're gonna add this apply plug-in line open up the build.gradle at the app level and add that over here and then in the dependency section this is where we're going to eventually add all the libraries for firebase but we're going to do that later just tap sync now to make sure that succeeded cool so now let's hit next and then let's continue to the console so i closed all other tabs except for the console tap on this button here for go to docs and we care about android and in particular if you scroll down you want authentication go into the android section and google sign in so we're going to follow pretty much this guide over here the first step is we already did the first couple here the next thing we need to do is add the dependencies for firebase auth so i'm going to copy that go into the build.gradle and add it right over here and one thing is that because we're using kotlin we can use the kotlin version of this library so you just add dash ktx here and tap on sync now to make sure i didn't screw anything up all right looks good and we already did the shot one fingerprint and one thing we need to do is in the firebase console we need to enable google sign-in so go back to here go to authentication sign in method and we want to enable google sign-in you need to add in a project support email tap on save okay that's enabled now so one thing you can do here now is open up the google sign-in to your android app but we're going to borrow some pieces from here the first thing i want to do actually is i want to integrate in the sign in button into our app this ui so copy that go into the activity log into xml which represents the ui for the login activity and in the design tab i'm going to just drag out a text view into the constraint layout have this be let's say 100 from the top and it's centered horizontally that looks good and let's make the text here say emoji status and i want this to be large because it's the title of our application so make this display one maybe and we'll also update the font let's make it sans-serif medium to make it a little bit darker cool so now we can go into the code tab and let's paste in the xml for that google sign in button and one thing i want to do is just update the id to make it more match the style i like to use in a kotlin app which is btn sign in let's see what this is complaining about this view is not constrained yeah so we now let's go back into the design section and figure out how to constrain it um i'm gonna import center it horizontally this is a little hard to do because we're not seeing the actual ui here so first what you should do is build the app and this at least should show up in the ui cool now we see it and i want the top constraint to be below the text view and i wanted to have a margin let's make it like 32 that looks pretty good cool and so if we actually run the app now hopefully we should see the google sign-in button awesome then nothing happens when we click on it which makes sense we need to add the click listener next so when the user taps on the button what we're going to do is launch an intent to sign in with google and that intent is going to be created for us using the google sign-in library so if we go back to the guides then go back to the firebase guide and we're going to copy this these are options to configure google sign-in this is the kotlin code tab so now we're going to go into login activity in the oncreate method just paste that in you'll probably need to import some things and one thing i'll just help to demystify a little bit here is that we have a request id token and we never defined this string but if you actually go into the definition click the definition of here you can see that we're getting these values xml the string is coming from google services so when we integrate the library we're getting all of these strings automatically so that's one thing one nice thing that the library takes care of for you the next thing we need is the google sign-in client and you can get that by calling the static method on google sign in you say dot get client and you pass in the context and the options which we just defined gso so we capture that into a local variable called client and now we can hook up the click listener on the button so we called the id of that button button sign in so i'll say btn sign in dot set on click listener i wanted to pause quickly here because i wanted to explain what you can do if you are seeing btn sign in highlighted in red android studio is complaining that there is no variable defined btn sign in and the reason you might be seeing this is because more recent versions of android studio have changed how the activity should reference views that are defined in the layout file and so let me show you in a really simple way how you can fix this so what you want to do at the top of the class inside of the activity you're going to declare a private late init var and call it the same as what the variable is called so in our case it's btn sign in and it's going to be of type button now what you want to do is after the set content view line in the oncreate function we are going to set the value of this to be find view by id and here we're going to reference the id of that view so it'll be r.id.btn sign in and now you can see that the red error went away and we should be able to proceed exactly as i'm showing in the tutorial so as you go through this whole series anytime you're referencing anything from the layout file you you might want to do something like this just because that will be future proof regardless of what android studio version you're on okay now let's go back to the way i was doing it in the series but don't get confused by this and we're going to create a sign in intent here and the intent is coming from the client dot sign in intent and so now we need to start an activity but it's not just starting at activity we also want to get the result of that activity did the authentication of google succeed or fail so that's why we're going to call start activity for result and that requires two parameters one which is the intent which we just defined sign in intent and the second is a request code which can be kind of any arbitrary number so i'm going to define it as a constant called rc google sign in and we're going to define that inside of a companion object which is basically a way to hold all the constants or static variables in your class so i'll say private companion object rc sign in and then this is going to be private const valve and you can kind of pick whatever you like i'm going to make mine 4926 and then one more i'll add is a tag because we're also going to be logging some things and the convention i always use is the tag name is always the class name okay so when star activity for result executes that's going to launch the google sign in flow and that flow is going to give us a response in order to capture that response we need to override a method called onactivityresult in order to help with that let's go back to the guide and scroll down a bit and here you can see the onactivityresult so i'm going to copy that and paste it in right below the oncreate method so right here and then we called the request code rc google sign in so i'm going to change that and you'll also you're going to have to import some things [Music] well i'm just going to clean this up a little bit um and basically what's happening here is that if the request code of the on activity result is the same one that we launched with that means that we heard back from the google sign in intent then the sign in was successful then we're going to call this method firebase auth with google so in order to define that again let's go back to the guide and here is firebase auth with google so let's copy that i'm going to define it as another function here and again we're gonna have to import some things here we need to define the firebase auth library so again go back to the guide and right here um we're gonna have a late init var auth at the very top [Music] and then this auth is equal to firebase auth is going to be how we initialize it that happens in the oncreate method let's import firebase auth and then inside of the oncreate we'll set it equal [Music] and the thing that we skipped over here on number three is when the activity starts up the first thing we want to do is check if these are signed in because if they're already signed in we don't want to show them the login ui we want to show them directly the main ui so we're going to actually copy this so onstart is a lifecycle method on the activity which happens after the oncreate so we're going to execute this and we're going to have this update ui method which we can just define create function update ui which is takes in a user as a parameter and we'll fill that in in just a little bit but going back down here let's finish off what we were doing here so now we have the firebase auth defined they're doing some sort of asynchronous requests here to look at the credential and then see if we can actually update firebase our project create an account or sign in to an existing account with this credential um i don't want to use a snack bar i just want to use a toast so i'm going to say toast this and then copy the message authentication failed and the length can be short that's fine and then that's all we need so if in the success case we call update ui with the user in the fail case we call it with null so we need to be able to handle the null firebase user here which is what this question mark indicates all right so we're almost done now um what we want to do in update ui is we want to actually update the ui which basically means we want to navigate to the main activity i'll leave that as a comment here and there are two cases here right one is if the user is null that means we shouldn't navigate to the main activity they should try again and figure out how to log in properly so in this case we're going to just log something at warning level and you want to return early here otherwise if we've gone past that if statement that means that we want to actually go to the main activity and so in order to do that we say start activity and we pass in an intent here and the intent is going to be um two parameters one it's going to be the context the second parameter is the destination where do we want the user to end up and we want the user to end up looking at the main activity so i'll say main activity [Music] and the last thing i want to do which is actually a common bug that i've seen with login uis is that we want to finish the activity here and what that means is we don't want this login ui to show up in the back stack once the user has gone to the main activity and so by having this line here finished that means that we're going to close down the login activity and that'll make a lot more sense to the user if they click back from the next screen let's try it all right so i'm going to hit sign in and i'm going to log in with my personal account and let's open up logcat and just see what happens i'm only going to filter by login activity [Music] and it's okay we can see that we did call firebase auth with google with some token and then we got a success in the sign in with credentials which is awesome and so we did properly navigate to the main activity which is where we're seeing hello world and let's check that this worked by going into the firebase console go into authentication and now we do see that there's one user signed into the app great the last thing i want to do in this video is i would like to add a menu option in the main activity menu so that we can actually allow the user to log out of their account the way that works is go back into android studio and i'm going to create a menu resource directory so make a new android resource directory of type menu and inside of here we're going to create a new menu resource file called menu main [Music] and we're going to drag out a menu item and the title will be log out and the id can be mi menu item log out that's all that we need to do from the menu perspective now we need to tell the main activity that this is the menu that you should be using in the menu bar so go into main activity and there's a function here that we want to override called oncreate options menu and so here we're going to say menu inflator this menu inflator is an attribute on the contacts so that's why we can just call it like that we call dot inflate and you pass in the menu resource id so it's going to be r dot menu dot menu main and the menu which is the parameter that we pass in right here and this function returns a boolean so we're going to return true here just to indicate that we provided the menu that should be inflated now we want to get notified when the user has tapped on that menu option for that we're going to call on options item selected we're going to override this method and here the idea is that we're going to check if the item selected which is the parameter here if the id of that is equal to dot id dot mi logout which is the id we provided to that log out menu option in this case i'm going to just log.i log at info level that we did log out and this now requires defining a tag so let's do that at the top we're gonna again have a private companion object with a tag private cost val tag and we're gonna have it be the class name [Music] and now we need to simply log out the user log out the user in order in order to do that we're going to do something quite similar to login activity in order to retrieve the firebase authentication instance so go back into login activity and remember how we have this late init var auth which is a handle on a firebase auth object i want to copy that over and then inside of the oncreate method we actually initialize it so oncreate we initialize that and now all we need to do is call this method off dot sign out and once the user has signed out we want to navigate them back into the login activity because they have no business now being in our app in the main activity right so i'll say val logout intent is equal to intent and then same thing here we need to have two parameters one which is the contacts which is going to be this referring to the activity and the destination for where we want the user to go which is going to be login activity [Music] and one other kind of nuanced bug here is that if they do log out we want to clear the whole back stack right we don't not only do we not want this main activity to show up in the back stack but anything prior to that we also want to do to dismiss and so for that there are some flags that you can set on the logout intent so i'll say logoutinintent.flags is equal to intent dot flag activity new task or intent flag activity clear task so with these flags set on the intent now we can call start activity with this intent all right that was a lot let's try it out and see if it works i'm going to open up logcat and now let's look at logs by main activity which is the log that we have right here so we should hopefully now see a menu option which is great and it should show log out so if we tap on that then hopefully we see the log out which is great and we do navigate properly now into the login ui so that's awesome we now have the basics of authentication and sign-in working in our app using google the next step is whenever a new user account is created that's when we want to trigger the cloud function to run which will automatically add that user into firestore and firestore is what is going to be powering the list of users and their emojis in this view in the last video we were able to set up our app to allow the user to create a new account or sign into their account using google the fun part starts in this video we're going to write some cloud functions which will automatically trigger some code to run every time a new user account is created and the reason we need to do this is because we can't store custom properties such as the emoji status inside of the same data where authentication data lives so we're going to have a separate collection in firestore which stores the name of the user along with the emoji status and that user is going to be created via a cloud function and so the very first thing i want to do is inside of our firebase console we're going to enable cloud firestore because we're going to have a cloud function which will write to cloud firestore so we're going to create the database here start it in test mode which basically means it's less secure but we're allowing everyone to read and write from the database as long as they're within a certain time range so tap on next and then pick a firestore location closest to you i'm in the us so this is the best one for me tap on enable so now we have our empty cloud virus store and the idea is that we're not going to populate this collection through the client and instead cloud functions will add users into a user's collection that we're going to have in cloud firestore so the interesting thing about this episode of this series is that we're actually not going to write any android kotlin code all the cloud functions are going to be written in javascript and it's going to be a separate directory or project altogether and so don't worry if you're not experienced with javascript i'm certainly no expert but i'll explain things as much as i can and it's actually only a few lines of code so it shouldn't be that difficult so open up this link for go to the docs again and actually we can close out the other tabs because we don't need to look at the authentication stuff again and what we're going to do is now look at the documentation for cloud functions and tap on get started so because we're going to be writing in javascript we're going to have to install some new software in our environment if you scroll down we already have a firebase project and we're going to now set up node.js and the firebase command line tool so i already have the firebase tools installed npm is a node package manager it's a way to once you have node which is a javascript environment then you can add packages onto node and so there's a tool called firebase tools which i already installed if you don't have that just google for how to install node or npm and then come back when when you're done now what you want to do is log into firebase and i think i've already done this but let's check so tap firebase login and okay so i'm already logged in this is my email so that's good now what you want to do is you want to create a new directory which is going to hold your cloud functions code so what i did is i went to the same directory where i had created the android studio project and i made a new folder a new directory in that same parent directory and i have the same name but i appended cloud to it this is a brand new directory which has nothing in it and so what i'm going to do here is run this firebase init functions call and what this will do is it will prompt you to set up this firebase cloud functions project so i'm going to tap an existing project link it to an existing firebase project that we have and ours is emoji status app and you can use either javascript or typescript typescript is basically a kind of javascript with types essentially we're not going to worry about that for now so just pick javascript do you want to use eslint which is basically a linter to catch probable bugs and that's always seems like a good thing so tap on yes and then you want to install dependencies with npm now tap on yes we do this will take a second or two to download all the dependencies once that's done now if you look at all the files in this directory it created a bunch of things for you and they're kind of documented over here in the guide and so what i want to do now is i'm going to open up this project this directory in vs code or your editor of choice so i have the directory opened up in vs code right over here and what we're going to do initially just is uncomment out the starter code and we'll play around with just this for the first minute and then we'll do our trigger based on when a new user joins our application what this is doing though is basically over http which basically means over the internet when we receive a request we want to send back hello from firebase as a response one other thing i want to do before we test that out though is if you scroll down you can import the required modules and initialize an app and so we're going to copy these bottom lines over here but if you go back so we have uh functions is equal to require base firebase functions we also want the firebase admin sdk because this is what is going to allow us to create a new user document when we get that point so just copy that in and we're going to use that later so now i want to come back to this we want to test out this hello world function which is uh functions.https basically being able to respond with this text whenever someone hits the corresponding url endpoint in order to test this out you can actually use something called the firebase cloud function emulator so we're going to skip all this tutorial stuff and just go down here and here it says emulate execution of your function so tap on or copy and paste this command firebase emulator to start go into your terminal well so what this is now saying is that all emulators are ready and you can actually you can see the logs from localhost 4000 so i'm going to go to that url and here you can see some of the ui associated with the emulator i'm going to go into the log section because that's the one that we care about and now i want to actually trigger the this function to run and the way we can do that is if you go back again to the terminal there should be a url here so one thing i forgot doing is you have to actually save this file index.js and then once you do that then you should see an output when you start the emulator for the url in order to hit that function which is the https function so i'm going to copy this and now if we go into the browser and hit that url then you can see the text that we wrote hello from firebase and if you look over here we can see the log output going back to vs code what we're logging is we're saying hello logs and that's what you're seeing from the logs right here and you're also seeing execution time but the actual response that we send back is hello from firebase and so this is the proof that we are able to talk to a cloud function at least locally the next thing i want to do is just show how do you send back an emoji as part of the response as opposed to just plain text and this took a little bit of googling but it's actually not that hard all you need to do is for sending back an emoji as a response you can say my favorite emoji is and then you have this backslash u which is indicating this is a unicode character and you put in the code of the unicode so in my case i like pandas a lot so i'm going to say 1f43c so now if i go back and hit this url again now we see the panda is updated so the objective now is we want to have this a cloud function run when a new user is created and the way we can do that is we can say exports dot and then you can name this function whatever you want i'm going to call it add user to firestore [Music] and here is where we are going to indicate to cloud functions that this function should be run automatically every time a new user is created so we say oncreate [Music] and this takes in as a parameter the new user which has just been created and here is where we define the body of the function so this code will get run every time the new user has been created and the job here is simply that we want to add a new document into the user's collection of firestore with the information about this user and so the way this works is we first get a reference to the the user so we'll save our user's ref the admin dot firestore dot collection and we're going to create a new collection if it doesn't exist already called users now all we have to do is return the setting of this new information in this user user's collection so the user's ref dot doc and the parameter here is we're creating a new document with this particular id and the id will be the uid of the user who just got created this user here so i'll say user dot uid and i want to call the set method and inside of set we set the different parameters of this new user document so the first is going to be display name which is just the display name of the user which we are getting from google and second is going to be the list of emojis which is their status and so here we have the opportunity to set a default emoji status for every new user in our app and so you can kind of make this whatever you want what i did is i just picked out three emojis that i thought were cute a panda which is the same one from before a herb emoji and a heart so basically pandas love eating plants or bamboo or whatever so we have this default emojis so now what we can do is deploy this to the cloud to our actual firebase project and then try creating an account one more time so in order to deploy this what we can do is go back to the documentation and we're now going to deploy functions to a prod environment so i'm going to copy this hit control c to exit out of the local emulation and then we're going to say firebase deploy dash dash only functions and one thing that you'll notice here as an error is that we don't have the proper account setup to be able to deploy cloud functions we need to upgrade our plan to be pay as you go so what you can do is this is actually pretty easy to update you can just hit that link and then right now instead of being on the spark plan which is free we're going to modify this to be on the blaze plan and don't worry it's still actually it's unless you're using unless you have a meaningful number of users in your app this will still be free so it really shouldn't matter in terms of you having to pay a bunch of money so i'm just going to go ahead and purchase it and if you are concerned you can set a budget alert so i only want i want to get alert alerted as soon as i spend ten dollars so i say set budget alert and you can close it okay so let's try it one more time i'm gonna rerun the same function the same command firebase deploy functions and so while that's running one thing we can do is if we go back to our console the true test of what we just did is if we create a new user account that should now trigger a cloud function and that cloud function should now show something in cloud firestore so in order to test that path we need to actually create a new user so i'm going to delete the user that we already have and then log into our app again and then that should trigger this path so i did that i deleted the user now it's going to cloud firestore and when we go back to our app now let's see if it finished okay so http error 403 i think this happens under this because we just upgraded our account let's try one more time so going back to the terminal looks like we did deploy successfully now so if we go into our running emulator let's log out because this user actually doesn't exist in reality anymore so now if we sign into the app let's see if this works but that should trigger is a new user being created okay so that seems like it worked because we were able to navigate to the main activity so if i refresh this page we should now see that user which is me show up okay that's great now if we go to cloud firestore and now we do see a new user collection user's collection which is awesome and here we have this document which is a display name of the user who just signed in which is me along with our default emojis it's amazing this is a indication that we have this kind of end-to-end flow working which involves authentication cloud functions and firestore in the next video our job is to update this main activity ui to read from cloud firestore read all this data and show it in this screen in the last video we wrote a few lines of javascript code so we had some cloud functions and basically what this did is every time a new user was created we added a new user document into firestore so now we're done writing all the javascript that we're going to need for this app i'm going to exit that and let's come back to our application and the idea for this video is we want to render a recyclerview which shows the list of all the users in the app along with their status and this is simply going to be querying that user's collection that we just created and one thing before we actually start coding is i want to show you what i did here is i created some fake users so basically here's the here's my actual user with the default emojis but i also went ahead and just added a few other documents to make the app more interesting while we don't really have other users so let me show you what i did i can just say auto id the field the first field is going to be display name it's going to be of type string and how we make elon musk a user for our app and the second field will be emojis and elon musk is probably thinking a lot about cars and rocket ships right so i'm going to paste in those two emojis and then tap on save cool so that added one more user document to the collection with the fields that we just declared so let's go back now to android studio and inside of main activity we want to basically have a recycler view here which fetches that data and displays it the first thing i want to do is go into the corresponding layout file for main activity we don't need the hello world and instead i'm going to drag out a recyclerview so we're going to add a dependency for that so tap on ok that'll take a second or two to finish and then i'm going to make the width and height be matched parent basically i want this recycler view to take up the whole screen height i'm going to give this an id of rv users go back to main activity and the idea here is we now want to set up the recycler view properly with an adapter and layout manager so when your data is coming from firestore as it is in our app then firebase actually has a really nice library which makes it a little bit simpler to set up your recyclerview and this is the page i have open here so if you if you google for firebase ui for android you should be able to find this page and this is what we're going to use to power our recycler view if you want a refresher on recyclerview and how it works which will be helpful to understand what we're doing here i'll leave a pointer for a video i created about that topic in the description so using this uh library all we need to do is we're going to add a dependency here for using firebase ui with cloud firestore so copy that let's go into android studio and open up the build.gradle file which is in the app module paste that tap on sync now and now what you should do is hit the link for firebase ui for cloud firestore and the first thing we need like most other recycler apps need is a model what is the data we're trying to render in each row or each element of the recyclerview and the data we're trying to render is one user so we're going to have a data class in kotlin which represents a user object so ideally this really should be its own class but just for the sake of expediency and kind of to make it all fit together nicely i'm going to define it right here inside of main activity so i'm going to define a data class here called user and there will be two attributes on this user the first is going to be a um a string which is for the display name and one of the things that's important to note about these data classes is that if you're trying to map them with a firestore data object you need to have a default value for each element of the data class i'm going to set this equal to empty string and then the other attribute is called emojis [Music] is also a string and also has a default value of empty string and these names should match up exactly with whatever you called it inside of the document over here so make sure that that's consistent so that that mapping can happen automatically for you all right so now we have the model defined now we want to actually make a query and the way the query is going to work is we're going to have to get an instance of firestore in our application and then query on the user's collection and then if you want to order by something but by first name for example or limit it somehow you can do that here so the first thing we need to do is add the dependency for firestore on android so i'm going to use the docs and let's um make sure you're on the kotlin tab and we're going to copy this go into again the app level build.gradle and tap on sync now and so the way you reference firestore is really simple actually you just copy this and then you put that at the top of your class where you want to reference firestore you have to import this great so now we have access to firestore with db so if we go back to the guide about firebase ui here's what the query might look like this is in java code so if you do a little bit of translation so in our case it's going to be val query is equal to dv dot collection and then our collection is called users and that's actually all i want you can kind of customize this if you want but for now i just want to get all the users in that collection [Music] so the next thing is we now need to set some firestore recycler options parameterized by the data and this will take in the query and then we're going to call the build method this is a builder class and we call dot bill to actually get an instance of this so i'll call val [Music] options is equal to fire store recycler options [Music] import that builder and this is again parameterized by the data class so i'll say user and then we have to set the query so in set query it takes in two parameters one which is actual query and second is the data that you expect to get from that query in an hour case we expect to get a list of users so we're going to specify here user class.java and one really important point here is that you need to specify a lifecycle owner basically you need to tell firestore when should this query be active and when should it stop and the way we do that is by setting a lifecycle owner is going to be the activity like the the parent class and so to reference that we'll just say this and then we call build so the next thing we need is an adapter for the recycler view and the adapter is responsible for telling us how can we take the data that we have and bind it to a view which is going to be shown in the ui if you scroll down here you can kind of take a look at what an adapter might look like so going back to the code what i'm going to write here is a val adapter is equal to and we're going to create a subclass of the parent class firestore recycler adapter and just implement the methods inline again if if we were kind of doing this in a more proper way i would actually recommend exporting this into a separate class but just for the sake of kind of keeping things simple i'm defining both the data class and the recycler view adapter right here in line so i'll just say object which means i'm going to create a instance of this class say firestore recycler adapter import that and then this is parameterized by by two things one which is a type and that's going to be user and then second we need a view holder and this view holder is an object which holds on to each view of the recycler view so one row of the recycler view essentially and we're going to define that we're going to call it user view holder [Music] and then this is going to take in options and then we actually have to implement methods here so first let's define userviewholder and userviewholder is simply going to just be a subclass of the recyclerview viewholder so i'm going to define that up here class userviewholder is a subclass of recyclerview.viewholder [Music] viewholder and then we need to add the constructor parameter which interstudio will do for us okay cool so now we've defined that um so now the subclass of firestore cycle adapter has to implement certain methods and that's what this is complaining about so just tap this on implement methods implement methods helper and there are two methods we need to override so select both of them and the job here is in oncreateviewholder we need to use a layout inflator to create a new view and on bind view holder we need to take the data at this position and bind it into this view holder again to really make this expedient and quick i'm going to use a built-in android layout for the concrete view holder and if you wanted to customize the layout at all then you should create your own layout but just to keep things simple there's an inbuilt one that will fit our needs so i'm going to say layout inflator dot from and we need to pass in a context here so i'm going to pass in this at main activity which is referencing the activity and then inflate and here's the inbuilt layout that we're going to use it's going to be a two text view layout android.r android.layout.simple list item2 then the next parameter is the parent which is the parameter that was passed in and finally attached to root we're going to pass in false here because the recyclerview will take care of attaching it or detaching it so capture that into a return value called view and then we're going to return a new view holder and the view holder takes in as a parameter if you remember from up here the view holder takes it as a parameter of view and so we're going to return here a new view holder it's a new user view holder with that view and then finally we need to now bind the data so there are two text views as part of this inbuilt layout let me show you if i go to the definition here let me only look at the code tab so this is a two line list item and there's basically a text view here which is a little bit larger and then there's another one which has an id of text two which is a little bit smaller so going back into main activity we're going to grab references to these two text views so val tv name is going to be the top one and this is going to be a text view is going to be um inside of the view from the view holder we're going to find a view by the id which is the one that we just looked at android r dot id dot text one then there's one more which is text 2 and this is going to be the textview where we're going to place all the emojis so now in terms of binding the data properly all we need to do is in the text view for the name we need to set the text attribute to be the name of the user so we actually have that passed in as a parameter here uh called model so i'll say model dot display name and then for the text view for the emojis we again are going to call the other attribute on the user model the model.emojis this should be tv emojis.text all right that's pretty much it so now all we have to do is let's use the adapter at in reference to the recycler view so we called the recyclerview we had we gave an id of rv users so i'm going to say rvusers.adapter is equal to adapter and the very last step is when you set a layout manager on the recycler view let's say linear layout manager [Music] import that and linear layout manager takes in one parameter at least the version that we're using which is a contact so i'll pass them this okay moment of truth let's see if this works we just wrote a lot of code to open up the emulator and hopefully now because we um are passing this query into the adapter it should automatically fetch the data and show it all right so that didn't work and it turns out that the reason was actually because i wasn't properly adding in the internet permission so what we can do is go into the manifest file and start typing user's permission and the very first recommendation here is you need internet permission so now that we've done that let's go back and run the app one more time okay and now you can see that we do get this data back so all of the information from cloud firestore is here and then one thing we can try which is super cool is if we go over here um and we had elon musk thinking about the car and the rocket ship which you can see over here let's edit this and maybe elon musk is not thinking about that right now he's thinking about pretzels and being happy so do that an update and immediately you can see how in our app elon musk his status got updated and that's the power of firestore and kind of the way we have this set up is that every time there's a change we're automatically instructing the adapter how to query for the data we get that and we bind the data properly so that's one of the things we get for free out of the box with this integration and the same thing works actually if a new user is created so if a new user signs into our app then we would get a new document in the user's collection and we would automatically get that data sent down to all the clients who are using this recyclerview so now we have a way to see all the users and their status which is super cool the next step is we want to be able to allow users to update their status right so in the next video we're going to add one more menu item which allows the user to write a new emoji status and then send it to firestore in the last video we built the functionality to allow the user to read statuses for themselves and all other users but there's no way to allow the user to update their own status so that's what we're going to fix in this video we're going to add one more menu icon here which is a pencil icon which indicates that the user can edit it and modify their status so to get started let's open up android studio and go to the menu main which is what we had added for the logout option so we're going to add one more menu item here and the title of this menu option is going to be edit status but no one's actually going to see the text because we're going to add an icon so the id first of all is going to be mi edit which is menu icon edit and we're going to add a new icon here so to do that android 3 is a pretty powerful way to create your own vector assets which is exactly what we're going to use using a lot of kind of open source icons so i'm going to go to drawable right click on it tap on new vector asset and then in terms of clip art we're going to search for something called edit which is this pencil icon and i'm going to just call this ic edit then tap on next and it'll automatically add it into the drawable folder so now that we've added that that'll be the icon so i'll just start typing drawable ic edit and one important thing here is we don't want this to be buried inside of the overflow menu for the main activity menu instead we want it to be shown as an action so in the show as action tap on always and tap apply and so what that did is that it brought up this menu option into the top level so if we run the app now we can see what this looks like we could hopefully see one more menu option here which is the edit pencil icon awesome so in order to register something and do something when this icon is clicked let's go back into main activity let me exit a few of these tabs and in the on options item selected we're going to have one more condition here for if the item id selected is equal to the one that we just added r.id.mi edit and in this case let's add a log statement just so we know what's happening so the objective here is we want to show a alert dialog uh which allows the user to update their status so i'll say show alert dialog to edit status and i'm going to delegate the work of that actually to a method called show alert dialog and then this is not defined yet but if we click on this red light bulb then android studio will define it for us and so the way we can create an alert dialog in android is actually pretty straightforward we're going to define a variable called dialog and this is going to be we're going to use the alert dialog builder this is the builder pattern and i'll say alert dialog and then we're going to use the one from android x appcompat dot builder and then this takes in the builder takes it as a parameter of the contacts so we'll pass in the activity which is an example of a context and then we'll just set various properties on here for example set title and the title we'll pass in is update your emoji and then another example of what we want to set on the alert dialog is the negative button we'll say cancel and then the listener we have to pass into the center here we're going to pass in null and set positive button and they'll be okay and again the listener will be null because we're going to be attaching the information about what to do when this positive button is clicked a little bit later on then we'll say dot show and in order to attach that listener when the positive button is clicked that's what we're going to do right here we'll say dialog dot get button dialog interface dot positive button and then set a click listener so this code gets executed every time the positive button is clicked so i'll just leave a log statement for that say clicked on positive button right now you can see that there's no way for the user to actually input anything right because we haven't set up a edit text here but i just want to show you what this looks like first so now if i tap on this edit icon you can see that we have this dialog popup it says update your emojis and right now if i tap on these like the options nothing really happens so what we want to do now is actually have a view show up in that alert dialog where the user can input their new status and so the way this works is you can have another method on the builder called set view and we're going to pass in the edit text here and i'm actually going to create the edit text manually programmatically right here but of course if you wanted to do something a little fancier with having control easy control over like things like the margin or padding i'd recommend you actually define an xml layout file where you can define the edit text but just for the sake of expediency again i'm going to define it right here so i'll say val edit text is equal to a new edit text and then this edit text that we're creating in kotlin code takes in uh context and for now i actually don't want to be concerned at all about how do we restrict the input of this edit text to only be emoji so that'll be something that we to do we mark as a to-do for the next video [Music] but for now now we have this edit text so when the user clicks on the positive button we want to extract the value out of that edit text so i'll say edittext.text.2string and then save that into a variable which is called emojis and entered so this is the what the user desires to update their status with right this emoji that they just entered if this input is blank which basically means is blank as kind of a helper function in kotlin is blank means either is the status empty or is it just consisting of white space so if they said space space space that's not something that's valid then we want to tell the user this is invalid cannot submit empty text and then you want to return here there's one more thing that we need in order to update the signed in user which is of course we need to sign in user right so i'm going to grab the user current user and that's coming from the firebase authentication object and if the current user is null which it really shouldn't be because you only ever see the main activity if you've logged in from the the previous activity login activity but just as a error handling we should just make sure that if this is null then we want to return early again so i'll copy this toast and just update the message here to say no signed in user let me fix the spelling [Music] okay so we'll return early here as well so here if we've gotten past both of these if statements now we want to update the update firestore with the new emojis so here what we can do is say db.collection on the user's collection we want to find the corresponding user and the way we do that we do that is we find the document which has that user's id because if you think back to our cloud function the document that we created has the same uid as the user that we just created so i'll say currentuser.uid and we want to now update this user with certain data and there are a couple ways you could input the data here the way i like which is i think the simplest is you can just put in pairs of data so you can say the field path which is in our case emojis that's what we call the attribute name and the value of this key is going to be emojis entered and once this is done you can now dismiss the dialog [Music] awesome let's try it so now hopefully we should see kind of a very plain edit text in the alert dialog and when we tap on the ok button the positive button we should be able to get the value out of the edit text and then update the emoji so okay i think we built the app properly if we go back to firestore let's look at my user and right now i have this panda herb and heart icon so i'm gonna update my emojis with something simple like i'm really in love so i have those three and now you can see it updated here and also in firestore you can see it got updated immediately as well so it seems like that works so the downside of this is that you know we're not actually restricting the input here so i could just say hello tap okay and actually we do update the status here to be hello and it shows up in the app as well which we don't want we want to restrict the input of that edit text to only be emojis so that'll be the job for the next video the job for this video is we would like to be able to restrict the input for what the user is allowed to enter in the text view to only be emoji so right now we're kind of in a bad state where the user has entered in hello i've entered in hello and we actually updated the status as hello and that defeats the purpose of the app right the purpose of the app is to be creative and and funny with different statuses that are only consisting of emojis let's go to interstudio and fix this we're going to add some filters on the edit text so let me show you what that looks like there's an attribute here called filters and this basically is telling the edit text how can you restrict the input of the edit text which is exactly what we want and this filters attribute will take in an array of filters i want to point out here that there are actually two separate filters that we want to apply one is the emoji restriction and the second is a length restriction so first is the emoji restriction that one's actually a little bit harder so i'm going to punt on that for now i'll get to it in a minute the input length is actually very simple to implement we don't want people to have statuses which are you know tens or dozens of characters long dozens of emojis long instead we really want to be concise about how many emojis we're allowing people to have and the way we can do that is with the inbuilt filter called a length filter so i'll say length filter is equal to input filter dot length filter and here you specify what is the maximum length that you're allowing and we're going to allow i'm just going to put a 9 here and the reason we're saying 9 is because each emoji is actually a unicode and a unicode character actually consists of multiple characters compared to plain text so i'm no expert in unicode but i can leave some pointers to some documentation but what i found is that most unicode characters are at least two characters long or up to four characters long and so when i say a max of nine that essentially means that we're allowing a maximum of four unicode characters or potentially as little as two if you got unlucky and you picked two unicode characters which equate to four characters so that's the first filter that we're going to apply length filter the second one we're going to have is an emoji filter this is a custom one that we're going to define called emoji filter and i'm going to make a new class out of this emoji filter i'm going to define this as a separate class and again you can sense the pattern here i'm going to define it inside of main activity you should probably be defining this into a separate class together just for cleanliness but just because it'll all fit together in main activity i'm going to do it right here so i'm going to define the inner class here called emoji filter this is going to be a subclass so it's going to inherit from input filter [Music] and you have to override certain methods here so i'm going to have entertainer help us with that there's a method here called filter and there's a bunch of parameters here which i'll explain a little bit about let me put this all in one line just make it a little bit more readable but basically the idea here is that whatever is attempted to be inputted in the edit text that is going to be this source parameter this first parameter and if we allow this input to be added to the edit text we're going to simply return source so if the added text is valid return [Music] source if it's invalid then we want to return empty string basically meaning that whatever you inputted is not allowed go back to just empty string so that we essentially don't modify whatever is already there in the edit text and you'll notice here that the return value of this method is car sequence and it's valid to return a string here because a string is actually a type of car sequence so let me show that to you if i just type in string and then i'm able to go to the definition you can see that the string class inherits from car sequence that's why you're allowed to just return empty string in certain codepaths okay so hopefully that makes sense uh with this pseudocode now the question is how can we identify what is valid emoji based on this source variable right and the reason why source here is a car sequence and not a car you might think okay i can only really add one character at a time in edit text that's actually not entirely true because when you have suggestions in the keyboard on android you can actually add in certain whole words and so the source might be multiple characters together which is why it's a car sequence and not just a single car and similarly an emoji is not one character it's actually multiple characters tied together so the way i want to build this is actually start with the invalid cases first so first of all if source is null because this is a nullable car sequence right or if the source is blank which basically means that it's just kind of empty text then i want to return empty string basically no need to modify whatever is already in the edit text [Music] otherwise i want to just add a log statement here so i say log i at info level and then i just want to kind of help us to debug what's happening here i'll say added text source [Music] it has a length of let's print out how long this car sequence is [Music] and now i can just say return source for now all right so let's just make sure that we're using this emoji filter i'm gonna put it inside of the array of filters and we're about to finish this to do so i'm gonna get rid of that as well okay so let me try the app right now and just see what happens based on the logs that we see let's open up logcat and i'm going to filter for main activity [Music] okay so if i open up the edit text and i start typing t for example so we are able to add a t and t like we expect has a length of one character however if i start using one of the autocomplete options such as thanks here then you can see the added text is the whatever is remaining after we chop off the t which is hanks and that has like the five characters and now let's actually just go back a little bit and add in an emoji like like this one so here you can see this emoji of the crying face has a length of two characters and there are a couple let me see if i can find one like this one uh this ribbon emoji has a length of three characters that's what i was saying that the emojis actually have variable lengths some are two some are three and then there's a few that are actually four and so we want to make sure that we accommodate that scenario now the question is how do we make sure that the input is valid emojis so one thing we can look at is is the character that's added have length of more than one character but that's not a perfect way of filtering out only emojis because like we saw if you add something from the autocomplete that will also give you something with more than one character and the way we're going to approach this which i think is the more robust way is we're going to iterate through each character of this source and check the type of it each character has a type and what i have found based on some googling is that every character of an emoji has a certain type of character and we're going to check based on iterating through this car sequence whether each character fits that one of those valid types and so let me just show you what are the valid types so i'm going to define a list here called valid car types and this is going to be a list of and then oh it's going to be character dot surrogate these are static variables defined on the character class so surrogate is one of them and the other two i found are non-spacing mark and character dot other symbol these are the three that i found which encompass what are possible unicode characters so turns out i was actually wrong and there are a couple other valid character types that make up emoji and so i'm going to leave a link to this just in the description and here you can see i did a lot more testing and i found that there are some emoji characters which have other character types and you might want to include this if you want a more robust way of checking for valid emoji and then one thing i want to do is i want to map this so right now you can see that these are all of type byte and i want to actually make all of these of type int so this this valid card types is a list of integer and the reason i want it to be a list of integer is because when we get the type of each input character from source it's going to be of type integer so now our job is simply to iterate through each character each input character in source and get the type of that that's what i was referring to as character dot get type and i'm going to look at the type of input character save that into a variable called val type and for debugging purposes why don't we log something here [Music] so um [Music] character type and then print out the character type here which is type cool and then what we want to do here is check is this type does it actually exist inside of valid character types if the answer is no that means that this whatever is being added is not a valid emoji and we should not be allowed to add it to that a text so i'll say if valid card types contains um type so if the list of valid card types doesn't have type inside of it that means that you know this is incorrect this is not valid so i'll say context is this dot main activity only and we'll tell the user only emojis are allowed and then return empty string basically invalidating whatever they've inputted and just returning empty string if we've gotten to the end that means that the added text is valid and then these other branches up here are if this is invalid so let's try it now and let's just see what the log statements tell us about the type of each character we'll run this go into the emulator and let's open up vlogcat okay so now if i add in t we should hopefully not be allowed to input that because it's not of the proper type so type in t and yeah we do see this toast message which has only emojis are allowed and the edit text is not modified which is awesome if you look at the logs you can see that the added text has one character and the type of this character is is uh two and if you look at the surrogate has type 19 non-spacing mark is six and other symbols 28. so it's 19 6 and 28. so basically every character of a unicode should be one of those and let's test that right if i now go to the emoji section and i do this birthday gift so here you can see the birthday gift has two characters and each are typed surrogate which is this 19 and the other one which had three characters that ribbon has the first two characters of type 19 which is surrogate and the last one of non-spacing mark this is how we're able to really be able to distinguish emojis are valid and things like letters are not that didn't work and also things like autocomplete which do have length of more than one character even though they're not allowed because the character type there is not going to be one of the three that we have put into the allow list so now if we go back to the app i tap ok so now instead of hello we updated the status and that it's also updated properly in firestore so now this is a really good way of sanitizing the input and only allowing emoji so if you built out at this point exactly what we have over here i would love to hear from you this is a really kind of cute simple app which actually integrates a bunch of firebase services and if we revisit this initial architecture diagram hopefully it all makes a little bit more sense now firebase authentication will trigger a function in firebase cloud functions whenever a new account is created that will create the new user document in the user's collection and that will get sent down to all the clients which are listening for updates on the user's collection and finally we just finished the logic to allow users to update their status and that's restricted to only being emojis so the cool thing about this is that there's so many ways you could extend this and improve this app to make your own uh the published version of the app that i have i did a couple things one is i improved the ui and i also added sorting by update time right because right now we are whenever you update the status it just kind of updates in place but you would like to be able to bring the users who updated the status most recently to the very top of the list so that's something that you could very easily do just by adding an updated time attribute and also you could do other things like maybe users want the ability to increase the length of their status and that could kind of be a premium feature you could have have people uh who update their status frequently get that functionality or it could be a paid feature there's a bunch of things that you could kind of be creative with or experiment with so if you do any of these i would love to check out your app and play with it as well drop me a comment and let me know that's all i had for this series i hope you enjoyed building it and you can take the concepts here and apply it to whatever else you want to build in the future i'll leave links to all the code that we wrote along with documentation that we referenced in the description don't forget to hit that like button and subscribe if you have any questions or comments let me know and i'll help as much as i can until next time see you later bye
Info
Channel: freeCodeCamp.org
Views: 61,615
Rating: undefined out of 5
Keywords:
Id: rfdQHOB3jCU
Channel Id: undefined
Length: 81min 32sec (4892 seconds)
Published: Tue Jan 05 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.