Building a to-do list app with SwiftUI and Firebase (Part 1)

Just another WordPress site

Building a to-do list app with SwiftUI and Firebase (Part 1)

[MUSIC PLAYING] PETER FRIESE: Hey, everybody And welcome to “Firebase Semi-Live,” the show where we code it live here and you watch it later In the next few episodes, we’re going to look into something that I am particularly excited about, how to integrate Firebase with Swift UI Apple Health released SwiftUI at WWDC 2019 And it has changed the way how we build UIs completely However, there seems to be some uncertainty about how to integrate Firebase in SwiftUI application So today we’re going to fix this I’ll show you how you build a simple task list application using SwiftUI, combine Firebase, Firestore, Firebase authentication, and sign with Apple Wow That’s a lot of stuff to get through We’d better get started But before we start writing some code, let’s take a look at how the application is going to look like in the end Those of you who use the iOS Reminders app will notice the similarities On the main screen, you’ll see that we’ve got a header and a button on the bottom And when I press the button, it will add a new line here for me to add a new task So let’s do this Let’s begin with implementing the UI Add the task And let’s add another one And then we need to connect to Firebase And then let’s add another one There is a big question mark What happens? And in the end, finally, profit All right So hopefully, by the end of this episode, we’ll have finished implementing the UI And one thing that I like to point out– so if we have a look at what’s going on on my screen here– let me show this So what we’re looking at is the Firebase console And we have a look at the Firestore instance that is running as the back end to my application here And if we look into that, you will notice that all the elements that I added to my task list already have appeared here So as one example, let’s change the completion state of this element here And if you pay attention to the completion state down there in the console, you will notice that once I change it in my application, it will be updated in Firestore Awesome So let’s get down to writing some code So let me bring up Xcode and then we will start writing the application Let’s minimize this window, this one as well And then we will get started with a new Xcode application We will use a single view application Let’s call it “make it so semi-live live.” And we want to use SwiftUI for the UI And let’s place it in this folder here All right So the first thing that you will see is that we’ve got our SwiftUI view here for the content view And this is the normal start for all of our applications But what we want to do first is we want to define our data model So let’s create a new folder to hold our data model So first of all, a new folder here Let’s call it model And then let me add a new file And this is going to be a Swift file Let’s call it “task” because we want to talk about tasks here So in our application, we want to track tasks And those tasks have a number of attributes that are important For example, they will have a title And they will also have a completion state Completed All right So why don’t we turn this into proper Swift code? So first of all, this needs to be a struct

And then let’s close this here And then we will turn these into properties [INAUDIBLE] title And this is going to be a string And the completed state is going to be a Boolean Right? So to make our job easier, let’s also define some test data that we can use while building the UI So let me hide this in the debug statement here And if And then, let’s create a collection of test data Tests data tasks, and it’s going to be a collection of tasks Implement the UI and let’s say this is true Connect to Firebase And this is false, because we haven’t finished this yet And then a couple of question marks And let’s have the profit element as well All right Cool So we’ve got some test data here We’ve got our struct to keep the data That’s great So I know this is a rather simple data model And you might be wondering, how to support advance use cases For example, keeping track of the due date and managing multiple task list And maybe even sharing data with other users and stuff like that So these are all great ideas And we will definitely look into them in later episodes of the series But for now, let’s focus on the simple things and just deal with tasks and whether they are completed or not Right So, what’s next? Oh, I know We need the UI So let’s go ahead and refactor our structure a little bit more So let me move those elements here into a new group And this is going to be the app group And then let’s do another group for all our views All right So let me pull this up here OK So we’ve got our app group, our model group, and our view group And let’s go back into our content view And instead of using the name content view, let’s rename it, and use something more meaningful So refactor rename, and let’s call it task lists view Hit enter to rename And there we go So let me increase the window a little bit so we can see more And then let’s have a look at how the UI looks like in the preview So by pressing option, command, and enter, we will open the preview window And it’s currently paused, but by pressing option, command, P, can resume And then, in a couple of seconds, we should see how the UI currently looks like And then we can start building the UI All right So currently, it just says, hello world And let’s change that and let’s change it to one of our tasks So implement the UI, that was one of our tasks Great So in addition to showing the title of the task, we also want to show whether the task is completed or not And we can use an image to do that So let me drag out an image view from the pilot here So, search for an image And then drag it, and place it to the left of our label, just like that And you will see that the source code has been updated Currently, we don’t have an image name yet But we can use a system image And let’s use circle And you will see that we’ve got a nice circle here

And then once the task is completed, we will use a different image to indicate that this is now completed All right So let’s turn this very simple cell into a list So come on, click on the H stack, and then select embed in lists And then we get five elements And you will notice it’s still just this one element, but we will change this in a couple of seconds Cool So we’ve got our lists We’ve got a cell We also now need a button that we can use to add elements later on So again, let’s use the palette And then find the button, and then drag it down here And you can see it At the bottom of the screen, it says, add button to a new vertical stack That’s exactly what we want So let go And you will see, we’ve got a V stack, the list is in the view stack, and the button is there as well So we want our button to say something like, add new task And obviously this needs to be in the string And then, currently it’s centered, that’s one thing we need to fix But we also want to have a nice icon to the left side of it So let me actually wrap this manually into an H stack And then insert an image here Image, system name, equals, plus, dot circle, dot fill This will give us a plus icon on fill up circle That’s great And then finally, let’s change the alignment of the button to leading So we can do that by clicking on V stack, opening up the UI inspector, which, in this data version of Xcode is broken But no worries Let’s use our inspector on the right hand side and choose left alignment So everything is left aligned So let’s add a little bit of padding and we do that on the button itself OK So that looks a lot better Cool So one other thing that we should do is– so currently the icons are very, very small And we should make sure that they are a little bit bigger so they’re really nice touch targets We can do that by going in and changing the image First of all, making it resizable And this obviously is a little bit too large So let’s go in and change the frame to, let’s try it 20 by 20 OK Let’s see This looks good And let’s do the same with our image up here in the lists All right So all the images are roughly the same size, which is nice because then they’re really nicely aligned And finally, let’s also make sure that we’ve got a nice title on the screen So we can do this by wrapping the entire current V stack into a navigation view Navigation view, and then indent this So there is an empty space up there, which will take our title And then we will need to set the title on the first in our child which is our V stack So a navigation by title is tasks Great All right So this is our very simple UI And now let’s go ahead and connect it to some test data So, if you recall, we have our nice little test data tasks collection over here in the task file

So what we want to do now is connect it to our list view here In order to do that, we’re going to introduce a new property here And first of all, let me fix the indentation OK Perfect So let’s introduce a new property here, let tasks equals test data tasks That’s it, and now we can go ahead And instead of iterating over just five numbers here, iterate over the actual collection of data So let’s do this So we’re iterating over tasks And now it complains that task is not identifiable So let may, e increase this So it says, the initializer requires that task conform to identifiable All right This is because the ListView needs to know which element is which, so that when you’re inserting a new element, it can tell them apart and the elements don’t start jumping around So let’s go and make task identifiable So make it identifiable And how can we do that? So because we need an identifier later on for connecting our task with Firestore, let’s introduce an ID, and make sure that, for now, it contains a unique identifier And we can do that by using the UU ID clause And get a UU ID and turn it into a string like this All right And because we do this for all our tasks, our little collection down here will automatically assign a unique ID to each of those test data items that we’ve got So let’s go back into our view and now the compile errors should be gone Compiler is happy And now, let’s go ahead and actually connect all those items to the test data So first of all, instead of displaying static string, let’s rename this to task And then we can use it down here, task dot title And when I save this, the view should update on the right hand side And you can see that it’s pulling data from our test data collection That’s nice So before we also connect the completed state and to a different kind of image So maybe a full circle instead of an empty circle for the completed state Let’s refactor the cell a little bit So what we need to do is we want to extract those two elements here, the image and the text, into a separate view To make this easier, let me go ahead and turn this into a H stack again Because then we can just extract it Sorry OK So, fix the indentation, and then command click on the H stack And extract sub view And we’re going to call it task cell Great So we’ve got a couple of compile errors here that we need to fix So the reason why the compiler is complaining is that down here, in our new struct, it’s not entirely sure what task means Because task is unknown down here So we can fix that by inserting a new property here, call it task

That should fix the compile errors down here But obviously, we’ve got a new compile error up here So we need to tell it to inject this variable into the cell down there And let’s compile again All right Build succeeded That’s great So now, we can go into our task cell and make sure that we display the correct icon for the completed state So we want to display a filled circle when the task is completed And a non-filled circle when it’s not completed So currently, it seems like all the tasks are not completed, which is clearly wrong So let’s use a ternary if statement here So task dot completed And, if it is completed, we want to use checkmark dot circle dot fill And if it’s not completed, we will use circle OK Let’s see what that looks like And resume or a preview All right So it works We displayed the implement UI task as, this is completed Because in our test data we set, it was completed And all the other elements are not completed So this looks very, very nice And that’s it for our basic UI Before we go any further, let’s take a quick look at our architecture So let me pull up my preview application And let’s have a look at our architecture diagram So you can see that up here, we’ve got our views And each single view uses one view model And, in turn, the view model configures the view So, depending on the state of the view model, the view will look differently So for example, if we think back or if we look back into our UI, you can see that the check mark icon is only there because the view model for this specific task item said that the completed state is true So in this sense, the view model configures the view So where do the view models get the data from? So, ultimately, we will want to connect to Firebase and Firestore But we need a little helper clause to make this more manageable and to help us build a better architecture So we’re going to use a repository And the repository really is just there to make it easier to connect to Firebase So what it will do is it will open a Firebase connection, a Firestore connection, and it will pull data, and it will listen to updates And it will also take requests from the view model to add new elements to Firebase when the user adds new elements to their view And you can see this on the architecture diagram That the repository intern works with the storage, which in our case is Firestore, to store and retrieve data And in turn, it will return model elements, which are owned by the view model Right So let’s start and go ahead and implement the view model for our task cell view So let’s first create a new group here for our view models And drag it down a little bit And then we will create a new class, new file And let’s call it task cell view model All right

So it’s going to be a class task cell view model And it needs to be an observable object This is so that SwiftUI can observe any changes that we make to the properties on this view model And it also needs to be identifiable Because we want the ListView to use those task cell view models And as we saw before, it is important to actually have elements that are identifiable OK So each of those task cell view models will hold a reference to a task So a task But it’s not enough that we just hold a reference We need to make sure that this is published so that any change on the task can be listened to So let’s use the published annotation to make this a publisher All right So we need another property that helps us to make this identifiable And this is going to be the ID and it’s going to be a string And then, we want to also hold the name for the icon that we’re going to use to indicate the completion state So that, again, is going to be a published property, published variable, completions date icon name And this is the string And let’s make this an empty string And also, let’s make the ID and empty string as well This will help us with the initializer as you can see in a minute All right So in the initializer, we are going to do a couple of things So first of all, the initializer will take the task And then we want to operate on the task So first of all, let’s make sure that we keep track of the task So let’s assign it to our property here And then, let’s go ahead and run a map operation on the task And what we want to do is, we want to transform the task into a string And the string is going to tell us which icon to use So let’s use the transform signature here And we will have a task coming in And then we’re going to look at the task, and if it’s completed, we’re going to return check mark dot circle dot fill And if it’s not, we’re going to return circle So this probably looks very familiar to you, because it’s exactly what we’ve been doing in the UI But we’re extracting this into the view model now All right So the next thing that we need to do is we want to assign the result of the map operation to this property up here And in combine, we can do this by using the assign operator And we’re going to assign this to a property of self And it’s going to be completion state icon name And then finally, we need to keep track of our subscribers and assign them to a cancellable So let’s set this up up here Private or cancellables is a new set of any cancellable And in order to use that, we need to import combine All right

And now we can store this in this cancellables collection Cool So once again, we are mapping over the task And then, depending on its stage, we will return the name for the icon, store this into this property, and this is for memory management purposes down here OK so that’s the first thing we need to do And then the other thing that we need to do is we need to keep track of the ID And this is going to look very similar So, dot task dot map and we’ve got a task coming in And we will return the task ID and then we’re going to assign it to the ID property And then let’s store this into the cancellables Cool So that’s our task cell view model So one view model down, we need another view model So you might be wondering, why do we need two view models? The reason is that we’ve actually got two different views So we’ve got the ListView itself, and we’ve got the cell view So this view model that we’ve currently built is for the cell And we now need to have a view model for the list as well So let’s create a new class and name it task list view model And let’s impart combine And it’s going to be a class as well a task list view model And it’s an observable object It does not need to be identifiable, because it’s basically the wrapper around all the elements that we’re going to display in the list But it has a property to keep all those task cell view models So task cell view models is an array of task cell view model And let’s create an empty array when we initialize We also need the cancellables All right And then, here is our initializer And in the initializer, for now, we will still operate on the test data, and we will convert all those test tasks into little task cell view models And this is actually pretty straightforward So task cell view models, equals tests data tasks dot map Oops That was a little bit quick Let me do it this way All right So, for each task that we get, we will basically return a task cell view model And we will just send in the current task Cool So we’ve got our two view models And now what we need to do is we need to bind them to the UI So let’s go back into our list view And what we need is a reference to our task list view model So let’s do this It is a variable task list view new model And we will instantiate this And then, so that we can bind the UI to it, it needs to be an observed object This will allow SwiftUI to listen to any updates

that this is going to produce All right So missing argument for parameter task in core Oh, yeah I know why Because this is the wrong class So task lists view model That’s the right one OK So now, instead of iterating over this collection of tasks that we’ve got, we will instead access our view model and iterate over the tasks collection in that view model OK Let’s do it So task list view model And we need to iterate over the task cell view models in there So, compiler is still complaining a bit So let’s do a little bit of cleanup here So first of all, this is going to be task cell view model And then, we need to refactor the task cell as well down here So again, we’re going to use an observed object And this time, let’s call it task cell view model And it is a task cell view model All right And then, let’s remove this, because we don’t need it anymore And then let’s fix the compile errors down here So first of all, access the task down here And then change this down there OK So this should be fine And then up here, we’re going to access this variable in our list Cool So this looks good Let’s see if it compiles Looking good so far Build succeeded OK So let’s run the application and see if everything works as before And instead of running the application, let’s actually use the preview down here Because we can use this little run button to run the application And let’s see It takes a little moment Oh, probably I need to resume Both succeeded OK It’s working So, in case you don’t believe me, let’s also run it on the simulator Compiling, launching Let’s get the simulator All right There we go So we refactored our UI to use a view model architecture And this makes things a lot cleaner and it will lead to much cleaner code, especially in the views, as you will see later on And it’s a lot easier to connect to different sorts of back ends, which we all do in the moment So there are a couple of things that don’t work yet in our application And we need to fix them So, for example, we can’t add new elements to our lists And we can’t edit the elements in the list And we can’t mark elements as done So this is something that we are going to look into next All right So let’s go back to the code So the first thing that we need to do is we want to refactor our list items a little bit And the first thing that I’m going to do is I’m going to turn this list here into a for-each And this is because we actually want to iterate over all the elements in our collection And then, we also want to add one specific new element And this is going to be our editor element, if you will

And this is why we need to take the list apart So first of all, let’s just replace this with a for-each loop And the rest can stay the same And then embed this into a lists So let’s indent this Cool So, we also need to declare a flag that will help us to hide and show this very specific cell on demand when the user presses on this at new task button down here So let’s go ahead and add this as a state up here So state or freeze and add new item And let’s say it’s false for the moment So we want to hide it initially And then, in addition to this for each loop, we will display a task cell, depending on whether a present at new item is true or false So let’s make a little conditional here If present at new item is true, then you want to display a new task cell And it takes a new task cell view model And so that means we need to create a dummy task cell view model right here So let’s actually do that And then we need to create dummy task as well And it’s got an empty title And the completion state is false Right So this is our additional cell Currently, it’s not being displayed And we want to change that So whenever the user presses the button here, we want to show or hide this additional cell up there And you can do this by toggling the present at new item Boolean OK Let’s have a look if that works Quickly run the application OK When I press on the button, it will show or hide a new element And currently, that doesn’t do anything, because we’re still using a text instead of a text field So this is something that we need to change now OK So let’s go into our task cell And then turn this text here into a text field So let me just delete it to text field And then it needs to be boned to the title of the task And we can also provide a placeholder text So enter the task title, that’s what we want to display if there is nothing in there And then, we want to bind the text value of the text field to our title of the task in our view model So that’s the task cell view model And then the task and the title OK Let’s try this again OK Add a new element So you can see the place where all the text enter the task title And when I click in here, I can start typing And I can also tap into any of the other elements as well, because we’re using the same cell for this editor cell, and for any existing task that we display in our list as well Which is exactly what we want Because we want to allow users to just tap into the list and then change the elements without having to turn on edit mode or whatever So this is exactly what we want All right So the next thing that we need to do is we actually want to listen to any changes

that the users make so that we can take those changes from the cell view model and put it back in to the underlying data structure So the first thing that we need to do is, we need to add a little callback handler Because we want to listen to the uncommit event on the text field And whenever that is fired, we want to call back into our view that can then take the task that we’ve created and send it back into the underlying data structure OK So first of all, let’s add a new variable up here It’s called on commit And what we want to do is we want to send a task And obviously it doesn’t return anything So if we do that, the compiler will complain And it will say that there is a missing argument up here And there is a missing argument down here Which is fine, because down here, we actually want to handle the callback But up here, we don’t want to do that Because we already have an element We don’t need to add it to our collection And SwiftUI and combine are going to make sure that any changes that we make to an existing element gets reflected in the underlying data structure So what we want to do is, we will basically just provide an empty default implementation here Just like that And this should fix the compiler error message up here So that’s great The next thing that we want to do is, we want to capture the uncommit event on the text field And actually, let me make a little bit more space And hide the preview So we want to capture the uncommit event on the text field So let’s go ahead and listen for uncommit And then, when we receive this, we want to call this callback up here So self dot uncommit And what we want to do is we want to send the task back down All right So whenever you use a commits in the text field, so if they press the enter button, for example, then we will receive this callback And then we’re going to take the current task, send it into our callback, and then we can capture it in here All right So to do that, I’m going to use the fact that this basically is just a trailing closure And then we will get the task here And then we want to do something similar to this So we want to get the task view model, or the task list view model, and then we’d like to do something like add task But there is no method like that yet So this will fail All right So let’s fix this Let me just commit this out so we can compile And then we will go into our task list view model and implement a method that will capture our intent So at task, and we want to take a task And then we’ll just add it to our list of task cell view models However, we need to first turn it into a task cell view model So let’s do that And task view model equals task cell task cell view model

And it will take a task, and then we can add it to our collection And we will append it so it will be added to the end Great So let’s go back Uncommit this So this works fine One more thing that we should do is, when the user hits enter, we will insert the element into the lists So that means that the list will add a new line and that will look a little bit funny Let me show you what this means So let’s run the application So we’ve got our existing cells here We add a new one And I will hit enter And, as you saw, it inserted the new item into the collection SwiftUI picked this up, updated the ListView, and we still have this element down here And this looks a little bit funny So let’s actually make sure that we hide this cell down here, whenever we insert a new line And that’s actually pretty straightforward So let’s say, self dot present a new item dot toggle So this means, whenever we add a new element, we will hide or edit our cell Let’s have a look again OK Let me add a new element OK And you will see, we only have the new element The editor cell disappeared And when I add a new element, it will show up again, just as expected So that works great What still doesn’t work is updating the completed state So let’s do this as well And this is a little bit more– it’s easier So let’s go into our cell down here And then we want to make sure that whenever the user taps on the image, we will toggle the completed state of the underlying task So let’s go ahead and add an on tap gesture And then get our task cell view model, get the task, get completed state, and then just toggle it All right Let’s run the application once more And then, I can just go ahead and toggle the completed state of the items Beautiful And that’s it for today, folks Hope you enjoyed this short video about how to build a simple task list using SwiftUI In the next episode, I am going to show you how to connect this app to Firebase, and how to store the task data in Cloud Firestore Thanks for watching, and I will see you in the next one [MUSIC PLAYING]