0 1 00:00:00,510 --> 00:00:00,940 All right. 1 2 00:00:00,960 --> 00:00:07,590 So, now that we've gotten all the serious parts of our coding out of the way, we've got our messages being 2 3 00:00:07,590 --> 00:00:15,720 saved to our Firebase Firestore, we've got our login and registration routes planned out and working, 3 4 00:00:15,720 --> 00:00:21,690 now it's time to tackle some of those small user experience problems and improve the look and feel of 4 5 00:00:21,690 --> 00:00:22,780 our app. 5 6 00:00:22,860 --> 00:00:29,910 And one glaringly obvious problem that our app has at the moment is that when the user taps in this 6 7 00:00:29,910 --> 00:00:32,480 text field, the keyboard 7 8 00:00:32,640 --> 00:00:38,210 if it rises up will completely cover the text field as well as the send button. 8 9 00:00:38,250 --> 00:00:45,090 Now, on the simulator, we can toggle the keyboard up and down using command K. But the user who's using 9 10 00:00:45,090 --> 00:00:48,380 a physical iPhone cannot do this. 10 11 00:00:48,400 --> 00:00:50,580 Now, what is the solution? 11 12 00:00:50,580 --> 00:00:57,210 Well, the easiest thing would be to figure out what is the height of the keyboard, and then to lift this 12 13 00:00:57,270 --> 00:01:05,060 section here with the text field and the send button up to the top so that it rises up to about here, 13 14 00:01:05,310 --> 00:01:12,030 and it's no longer overlapped by the keyboard. But, unfortunately, especially if you're somebody who has 14 15 00:01:12,120 --> 00:01:19,550 a keen eye for detail, you'll notice that different iPhones have different sized keyboards. 15 16 00:01:19,590 --> 00:01:27,390 So that means that if we use a set or hardcoded number to lift this section up, then it will look a 16 17 00:01:27,390 --> 00:01:32,340 little bit weird depending on which iPhone the app is being run on. 17 18 00:01:32,430 --> 00:01:35,120 What can we do instead? 18 19 00:01:35,130 --> 00:01:43,230 Well, we could instead listen for notifications from the operating system when it's going to bring up 19 20 00:01:43,230 --> 00:01:50,760 the keyboard, then see which keyboard, and then write a lot of code to be able to check to see which height 20 21 00:01:50,760 --> 00:01:53,800 it is and adapt our code accordingly. 21 22 00:01:53,920 --> 00:02:00,860 But there's a much simpler solution because we now know how to use third party libraries. 22 23 00:02:00,900 --> 00:02:08,760 So because this is such a commonly needed functionality, whenever you create text fields, it's likely 23 24 00:02:08,760 --> 00:02:15,250 that you'll need some sort of way of moving it up, so that it doesn't get obscured by the keyboard. 24 25 00:02:15,270 --> 00:02:21,780 Lots of people have already written their solutions to it and they've packaged it into a module so that 25 26 00:02:21,780 --> 00:02:27,870 they can reuse it themselves when they're building new apps. And some of these developers are kind enough 26 27 00:02:28,110 --> 00:02:34,440 to share their solutions with the rest of us and we can tap into this functionality without very much 27 28 00:02:34,530 --> 00:02:35,280 work at all. 28 29 00:02:36,720 --> 00:02:42,120 So the package that we're going to be using in this lesson is something called IQKeyboardManagerSwift. 29 30 00:02:42,780 --> 00:02:48,230 And this is a package that's developed by Mr. Qurashi. 30 31 00:02:48,630 --> 00:02:54,360 And the best feature of it is it works codeless, so we don't actually have to write any code. 31 32 00:02:54,360 --> 00:02:56,990 We don't have to change anything about our app. 32 33 00:02:57,090 --> 00:03:05,310 It simply works in the background and lifts our text field so that it doesn't get obscured by the keyboard 33 34 00:03:05,640 --> 00:03:10,140 in all orientations and on all devices. 34 35 00:03:10,350 --> 00:03:17,350 If we scroll down, you can see that there's actually many ways of installing this particular package. 35 36 00:03:17,490 --> 00:03:24,390 And the most commonly used one is probably doing it via CocoaPods. And you already know how to do this. 36 37 00:03:24,390 --> 00:03:30,550 So if you wanted to, you can actually go ahead and incorporate this pod into your project right now. 37 38 00:03:30,750 --> 00:03:37,920 But because this developer has also enabled insulation with the Swift Package Manager, I thought it might 38 39 00:03:37,920 --> 00:03:43,860 be a good opportunity for me to show you how you can add a package with this Swift Package Manager as 39 40 00:03:43,860 --> 00:03:47,820 long as the project supports it. 40 41 00:03:47,820 --> 00:03:53,700 Notice how if we go to the GitHub repository for this project, you can see that on this main page of 41 42 00:03:53,700 --> 00:03:57,590 files, there is a file called Package.swift. 42 43 00:03:57,660 --> 00:04:02,330 This means that this package is able to work with this Swift Package Manager. 43 44 00:04:02,850 --> 00:04:09,150 However, most third party libraries, including the Firebase modules that we incorporated, don't have this 44 45 00:04:09,150 --> 00:04:10,590 feature enabled yet. 45 46 00:04:10,770 --> 00:04:17,220 So it's only for a small subsect of third party libraries that we can actually use the native Swift Package 46 47 00:04:17,220 --> 00:04:17,670 Manager. 47 48 00:04:18,420 --> 00:04:20,640 But how would we go about installing it? 48 49 00:04:21,600 --> 00:04:30,360 Well, if you find a project in GitHub that has a Package.swift file in its main directory, 49 50 00:04:30,480 --> 00:04:33,540 so notice how this is the GitHub domain, 50 51 00:04:33,540 --> 00:04:35,490 this is the user name, 51 52 00:04:35,490 --> 00:04:37,280 and then this is their package name, 52 53 00:04:37,290 --> 00:04:39,080 there's nothing that's coming after here, 53 54 00:04:39,090 --> 00:04:39,360 right? 54 55 00:04:39,390 --> 00:04:42,950 So we're in the root directory of this package. 55 56 00:04:43,020 --> 00:04:50,910 What you need to do is go ahead and just copy this URL, and then head over to your project, go to file, 56 57 00:04:51,390 --> 00:04:54,810 Swift Packages, Add Package Dependency. 57 58 00:04:55,320 --> 00:04:59,710 And now we're going to choose the projects that we want to add the package to. 58 59 00:04:59,730 --> 00:05:01,670 So we're not going to add it to our Pods. 59 60 00:05:01,680 --> 00:05:08,160 We're going to add it directly to our Flash Chat project. And this is also a good point to mention that 60 61 00:05:08,610 --> 00:05:15,270 while the Swift Package Manager is supposed to work alongside CocoaPods or Carthage, or any of the other 61 62 00:05:15,270 --> 00:05:23,150 third party library managers, at the moment, at this current moment in time, so end of October 2019, 62 63 00:05:23,340 --> 00:05:31,230 I'm finding that if you first saw CocoaPods and you add your Swift packages in the xcworkspace to 63 64 00:05:31,230 --> 00:05:35,250 your project, you have far fewer problems than if you do it the other way round. 64 65 00:05:35,280 --> 00:05:41,700 Say, you start off with a normal project, you add the Swift Package, and then you try to add a pod file 65 66 00:05:42,150 --> 00:05:44,220 and install pods onto that project, 66 67 00:05:44,220 --> 00:05:48,960 you get a lot of weird errors that the Xcode team seems to need to work out. 67 68 00:05:48,960 --> 00:05:55,110 So what I recommend is if you're going to use both CocoaPods and Swift Package Manager, then go ahead 68 69 00:05:55,200 --> 00:05:59,440 and install the pods first before you do the package manager side. 69 70 00:05:59,670 --> 00:06:06,000 But in most cases, you'll find that anything that's available on Swift Package Manager is also available 70 71 00:06:06,000 --> 00:06:06,990 on CocoaPods. 71 72 00:06:07,110 --> 00:06:08,580 But the reverse is not true, 72 73 00:06:08,700 --> 00:06:15,360 there's far more third party libraries on CocoaPods than on Swift Package Manager at least right now. 73 74 00:06:15,390 --> 00:06:21,090 So now that we've selected our project, let's go ahead and hit Next, and then we're going to paste in 74 75 00:06:21,150 --> 00:06:28,470 that URL that we got earlier on which points to the IQKeyboardManager repository on GitHub. 75 76 00:06:28,950 --> 00:06:34,160 So click Next and it's gonna go ahead and find the project. 76 77 00:06:34,170 --> 00:06:38,650 And now it asked for what rules you want to apply to your package. 77 78 00:06:38,670 --> 00:06:43,380 So in this case, we're going to update this particular module. 78 79 00:06:43,470 --> 00:06:50,520 So when the developer of IQKeyboardManager pushes out updates, we're also going to update our project 79 80 00:06:50,880 --> 00:06:57,820 to use the latest version of the keyboard manager up to the next major version. 80 81 00:06:57,840 --> 00:07:03,300 So at the moment, we're on 6.5.3 which supports the latest version of Swift and iOS13, 81 82 00:07:03,300 --> 00:07:09,990 and we're going to say that we want to update to using the next major version which i 82 83 00:07:09,990 --> 00:07:11,070 7.0.0. 83 84 00:07:11,580 --> 00:07:18,220 And the reason why you might want to limit your updates to major versions is that, let's say, 84 85 00:07:18,240 --> 00:07:21,120 that IQKeyboardManager updates to 8.0. 85 86 00:07:21,120 --> 00:07:26,790 Then it's very likely that it also entails an update in the Swift version, 86 87 00:07:26,850 --> 00:07:29,370 so it might be Swift 6 or Swift 7. 87 88 00:07:29,580 --> 00:07:34,040 And unless you're using the same version of Swift, then your project might break. 88 89 00:07:34,110 --> 00:07:40,880 You can also be even more careful and change to up to next minor update in which case 6.5 89 90 00:07:40,880 --> 00:07:42,310 goes to 6.6, 90 91 00:07:42,440 --> 00:07:46,730 or you can say the exact version that I'm working with right now. 91 92 00:07:46,790 --> 00:07:48,500 This is the least likely to break. 92 93 00:07:48,530 --> 00:07:52,780 But in our case, I recommend going with the next major update. 93 94 00:07:52,880 --> 00:07:58,880 That way we'll be able to benefit from the updates and bug fixes that gets brought to the package when 94 95 00:07:58,940 --> 00:08:02,830 iOS and Xcode inevitably changes. 95 96 00:08:02,890 --> 00:08:09,050 Now it's going to download that module and incorporate it into our project as a library. 96 97 00:08:09,550 --> 00:08:11,360 So go ahead and click Finish. 97 98 00:08:11,440 --> 00:08:17,530 And now when you take a look inside the left-side pane, you'll notice that down at the bottom, we've got 98 99 00:08:17,560 --> 00:08:23,250 our Swift Packaged Dependencies is added and we've got our keyboard manager right there. 99 100 00:08:23,620 --> 00:08:24,400 That's it. 100 101 00:08:24,400 --> 00:08:30,400 That's all we have to do. We didn't have to go into Terminal and we didn't have to do anything extra. 101 102 00:08:30,400 --> 00:08:36,970 This is why it's a really nice way of incorporating third party libraries into your projects in Xcode 102 103 00:08:36,970 --> 00:08:41,060 because it's inbuilt to the existing tooling. 103 104 00:08:41,290 --> 00:08:46,810 But unfortunately, right now, there's just not enough coverage and there aren't enough developers who 104 105 00:08:46,810 --> 00:08:49,930 are making libraries for the Swift Package Manager. 105 106 00:08:50,560 --> 00:08:55,990 I think in two years or three years, the situation will probably change and we'll end up with a much 106 107 00:08:56,080 --> 00:08:59,350 easier way of using these third party dependencies. 107 108 00:08:59,920 --> 00:09:07,750 So, now that we've incorporated the IQKeyboardManager package, all we have to do to enable it is to 108 109 00:09:07,750 --> 00:09:16,450 go to our AppDelegate.swift file, import the IQKeyboardManagerSwift module, and then inside 109 110 00:09:16,450 --> 00:09:18,160 our didFinishLaunchingWithOptions, 110 111 00:09:18,280 --> 00:09:21,960 go ahead and enable the keyboard manager. 111 112 00:09:22,150 --> 00:09:27,700 Now, even though it's not showing that down here under the Swift Package Manager, you basically have to 112 113 00:09:27,700 --> 00:09:32,900 do the same thing whether if you're using CocoaPods or Carthage, or Source code, or SPM. 113 114 00:09:33,850 --> 00:09:42,100 So let's go ahead and open up our AppDelegate.swift, and then import that module which was called 114 115 00:09:42,190 --> 00:09:49,690 IQKeyboardManagersSwift, and down here just below where we've created our Firestore database, 115 116 00:09:49,690 --> 00:10:02,590 we're going to go ahead and tap into the IQKeyboardManager.shared.enable, and set it to true. 116 117 00:10:02,730 --> 00:10:11,070 And we're now ready to go ahead and run our app. And now that we've enabled this third party library, 117 118 00:10:11,130 --> 00:10:18,870 notice what happens when I tap in the text field, it automatically scrolls up the rest of my screen and 118 119 00:10:18,870 --> 00:10:23,020 brings the text field to within view of my keyboard. 119 120 00:10:23,070 --> 00:10:29,050 And if you want, you can even do some more customizations with IQKeyboardManager. 120 121 00:10:29,400 --> 00:10:33,990 So for example, I don't really want this toolbar up here where it says done, 121 122 00:10:34,110 --> 00:10:42,210 it seems a little bit extra. So what I can do is I can go over to the properties and functions of the 122 123 00:10:42,210 --> 00:10:43,440 IQKeyboardManager, 123 124 00:10:43,800 --> 00:10:49,890 so these are all the things that you can do with the keyboard manager, and one of those things is to 124 125 00:10:50,340 --> 00:10:52,950 disable the AutoToolbar. 125 126 00:10:52,950 --> 00:10:56,500 This basically relates to this little area right here. 126 127 00:10:56,670 --> 00:11:03,690 And if I don't want it, then in the same place where I enabled my IQKeyboardManager, I'm going to tap 127 128 00:11:03,690 --> 00:11:12,300 into the keyboard manager and tap into the shared keyboard manager, and go to the enableAutoToolbar 128 129 00:11:12,300 --> 00:11:16,630 property, and set it to false. 129 130 00:11:16,900 --> 00:11:25,820 So, now if I run my app again, you can see that when the keyboard comes up, it doesn't go as high because 130 131 00:11:25,820 --> 00:11:28,930 we've gotten rid of that toolbar. 131 132 00:11:29,060 --> 00:11:35,360 Now, the final thing I'd like to be able to do is to be able to dismiss the keyboard if I click away 132 133 00:11:35,360 --> 00:11:36,050 from it. 133 134 00:11:36,050 --> 00:11:42,380 And right now, if I click anywhere on my table view, nothing actually really happens. But if I take a look 134 135 00:11:42,380 --> 00:11:50,180 at the keyboard manager's documentation right here, you can see that there is a property called 135 136 00:11:50,180 --> 00:11:58,680 shouldResignOnTouchOutside. And this resigns the text field, which means the text field is no longer selected, 136 137 00:11:58,730 --> 00:12:04,790 it kind of deselects the text field effectively if touched outside of the text field. 137 138 00:12:04,790 --> 00:12:11,360 So that means when we tap anywhere other than the text field, it's going to dismiss our keyboard. 138 139 00:12:11,420 --> 00:12:13,580 Let's give that a go shouldResignOnTouchOutside. 139 140 00:12:13,580 --> 00:12:18,320 And I want to pose this as a challenge to you. 140 141 00:12:18,320 --> 00:12:20,540 Can you implement this behavior? 141 142 00:12:20,540 --> 00:12:26,540 Pause the video and write the code so that when we click away from the text field, our keyboard is dismissed. 142 143 00:12:26,630 --> 00:12:32,560 I'll give you a few seconds to pause the video before I show you the solution. 143 144 00:12:32,640 --> 00:12:33,120 Ready? 144 145 00:12:33,120 --> 00:12:37,530 Here's the solution. Again, same as before, 145 146 00:12:37,530 --> 00:12:46,540 and then the property that we copied over just now, and then turn it to true. So now when I tap on the 146 147 00:12:46,540 --> 00:12:53,560 text field, my keyboard responds and pops open. But if I tap away from the text field, it dismisses the 147 148 00:12:53,560 --> 00:13:01,690 keyboard which is a really nice behavior that we've gotten for pretty much just a single line of code. 148 149 00:13:02,020 --> 00:13:04,610 And that's the solution to the challenge. 149 150 00:13:04,750 --> 00:13:11,890 The very last thing I've noticed is that our cell, because it's created from our reusable message cell 150 151 00:13:11,890 --> 00:13:17,770 here, it's still allowing selection which is what's causing this gray background to show up. 151 152 00:13:17,830 --> 00:13:25,750 So we have to select our cell and go to the Attributes Inspector and disable the user interaction checkbox 152 153 00:13:25,750 --> 00:13:28,130 right here. 153 154 00:13:28,190 --> 00:13:35,790 And then, now even if we select these cells, they won't turn gray, like as if it'll do something when we click on 154 155 00:13:35,790 --> 00:13:35,910 it. 155 156 00:13:36,540 --> 00:13:37,660 So that's it. 156 157 00:13:37,920 --> 00:13:41,840 That's all you had to do in order to get this brilliant behavior. 157 158 00:13:41,850 --> 00:13:48,480 This automatic animation, we're basically getting with no code at all, and it means that we can focus 158 159 00:13:48,510 --> 00:13:56,370 on creating the custom parts of our app making our app different from other apps using our creativity, 159 160 00:13:56,700 --> 00:14:03,420 rather than doing a lot of this boilerplate and routine stuff that we might need in a lot of apps. 160 161 00:14:03,420 --> 00:14:04,340 In the next lesson, 161 162 00:14:04,350 --> 00:14:06,560 we're going to be tying up some loose ends 162 163 00:14:06,670 --> 00:14:14,970 and we're going to see how we can get our app to display a different format of message if it came from a 163 164 00:14:14,970 --> 00:14:20,630 recipient versus if it's a message that we sent. For all of that and more, 164 165 00:14:20,700 --> 00:14:21,750 I'll see you on the next lesson.