Let's build WhatsApp with React Native and AWS Amplify [p4] šŸ”“

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's up not just developers welcome back to a new tutorial welcome back live stream today is Sunday and we are Sunday Friday today is Friday and we are continuing the build that we have started previous weeks and today specifically I'm preparing something for you very interesting today we're gonna Implement in our chat application we're going to implement uh media files we're gonna Implement uh features that will allow our users to send images send videos in the chat in the chat rooms and share like nice memories nice photos with with people so um what exactly we're gonna do we're gonna start by setting up our AWS storage that will allow us to use S3 buckets to store our images and our videos in Cloud then we're gonna work with uh image library to allow the users to select images from their library and then we're gonna upload them to S3 after that we're gonna see how to implement full screen image viewers and later on we're gonna Implement a feature where the user will be able to upload multiple images not just one at the end we're gonna take this solution and make make it more flexible in order to allow us to send different attachments not only photos and by the end we're gonna also Implement uh sending videos and we're gonna see how we can send two types of different Medias videos and photos all right so uh how are you doing guys in the life in the live chat are you ready for today my deal is hello how are you doing Larry Robert Catalin hello guys so I think we uh we can get started uh previous time uh during the uh previous tutorial if you didn't see it you can check it out I'm gonna try to link it somewhere on the top uh and also you can find the link in the description below uh during the previous time we implemented uh like a little bit more advanced back-end features like sorting the messages listening for new messages and now whenever we send a message here it's gonna right away appear and that's the same if I'm gonna connect with a different phone and I'm gonna send messages we also implemented group chats so now you can go ahead here see who are the participants you can invite even more people there you can select them from here and create groups with your contacts and yeah that was um this is the status of our project until now I really like how it's shaping up and I will try to get in in as many details as possible to have a very complete chatting application so yeah it's a it's a fun project I hope you are enjoying uh building it together with me and if you do make sure to subscribe to the channel gonna do it like this make sure to subscribe to my Channel Down Below because that will help us a lot to reach more developers and help more people from the community so um last yeah now uh what do you need to do as a prerequisite for following this tutorial is to uh if you need the source code like the starter project to uh to follow along then you can download the asset bundle following the link in the description below and where you'll find the part 3 of a source code from part three and in that way we are all gonna start from the same from the same yeah place however if you are following along and you're implementing it yourself you can skip this part because yeah like you can continue with what you have already but if you want to receive this uh guide that you see here with all the called Snippets and step by step everything then yeah like it's also in the description below you'll receive it on your email so um yeah let's start by setting up our AWS storage and while uh we're gonna wait for things to deploy we're gonna have a chat with people from from the live chat so for that uh we're gonna have to go to our amplify Studio page let me check that okay so here is amplify let me zoom in a bit and yeah let's open our WhatsApp clone and launch our studio now um when we are in our amplify Studio from here we have to set up the first step yeah like is to set up the storage module and to do that we're gonna go to the setup here and Storage uh yeah give me one second I was checking in our environment but yeah in your case this is what you should see a page where we will set up our storage first of all give it a name for the bucket I'm Gonna Leave It by default and let's allow the sign in users to upload View and delete uh files from our storage I'm not going to give any permission to the guest users and I'm gonna press create bucket to deploy and create our S3 bucket this process is going to take around one minute and after that we're gonna be able to start uploading images to our to the cloud foreign here you can find more information about all of these tabs and yeah if you get stuck check it out here I'm gonna keep this up to date all right foreign we're waiting for the deployment of storage to complete let's go ahead and continue with the next step because we still have to implement to install some libraries to work with image picker so for that let's open the S3 PK image from the library and um in order to to yeah like to select an image from the phone Library we uh we can install Expo image picker library and that will allow us to to do just that so let's come back in our project I'm gonna also zoom in here let's open a new terminal and let's install the Expo image picker foreign we're gonna go in our components and we have the input box the input box is this part down here that is responsible for creating new messages at the moment we simply have a text input here that um it has like the state variable and whenever we press send we simply send the text message as a new message what I want to do now is um let's launch the image the library to pick an image whenever we press on this plus icon so for that um for that I have prepared here that the function that will help us to pick an image so let's get this function in our application and let's look what it is doing uh so come on pick an image from here no you don't want to copy now yes pick an image so what we're doing here we first have to of course import image picker so let's make sure that we are doing that at the top of our file let's import everything as image picker from x-bomb image speaker Now using this image picker we are launching the image library and we are requesting that um we allow the user to select all media types here you can select if you want only photos so I think uh dot images and I think I'm going to start with images and then we're gonna slowly Implement like all media types as well here you can provide the quality of a image um where one is full quality and like um if you do 0.5 it's going to be it's gonna be uh processed and the image will be the size of the image will be less I'm Gonna Leave it one for now and let's consolock the result to see what's happening here lastly we need to attach this we need to call this peak image function whenever we click on this icon one of the plus icon our plus icon is here we can see plus and the good thing is that the icon has already a on press event and we can right away save it whenever we press we want to pick a image foreign we also need a state variable where we will save the URL of the image so at the top here below the text let's add the state variable for our image and let's do set image here which initially is going to be equal to null save now let's go ahead and try to press on this plus icon if I press it we should already see the um the image Library open for us so here you can select one of his images and it's going to be selected the thing is that we are not displaying it anywhere as we can see here from a state variable it's never used but we are setting it in state and if we check the console log that we did there we should see information about the the file so the file as you can see has a property canceled false and in case the user will cancel this request and simply go back we're gonna receive an object we've canceled through but if he chooses an image then we're gonna have information about that image such as the height type is image the URI which is the um the path to the local image and the good thing is that we can use this URI send it to a normal like crack native image and it's going to render it properly and lastly yeah like as we see here like also the weave for example so what we can do here uh let's see from here um yeah so in our where we are rendering everything here I want to display the selected image just above our input so because our input is all of this not the input but the input box is all of this save area view container this is the the gray one I will add I'll basically start by putting them into um fragment because above is I want to to render the image but I don't want to render the image always I want to render the image only if it is selected so if image then let's render let's start with a view and here we can render the image source uh URI will be our image and what else and here for the style let's go with Styles dot image selected image let's call it selected image because that's selected image okay selected image um and what else what else okay we have this image let's go ahead and try to style it so I'm gonna come here so for the image I'm gonna start by simply defining width and height and I will start with like 100 by 100 just to see if it works I'm gonna go into a chat room and I'm gonna try to select an image from here can find variable image because we have to import it from react native save and now are you gonna work now go to chats let's select an image and right away we see the image here um perfect so I'm not gonna spend a lot of time on our Styles let's go ahead and um copy these styles from from the guide because the focus of today is not styling and I will replace them here with attachments attachments container now let's go ahead and add the attachments container to our view here Styles attachments container and what I wanted to do here I wanted to add um yeah resize mode we need to add to them resize mode contain in order to display the image fully and um lastly I wanted to give the possibility uh to the user to delete a selected image at the moment it's not possible but if we're gonna add um an icon for material icons highlight remove let's copy it from here if we're gonna add it after the image and by styling it remove selected image as an absolute position we added these x button at the top right corner of our image and now we can press on this icon and the image is removed because on press we simply reset the image to null that's the only thing that we do all right so I think we are done with selecting an image from our library yes that's actually true now let's go ahead and come back to our setup storage here because we initiated the update of our backend and let's go ahead and see if it's ready Yes actually it is already uh done and it is ready here so what we can do is we can uh pull these changes but before we do that we will we still have to do one extra change to our data to allow us to attach images to messages my event of a tutorial I'm gonna show you a better approach of how to do this and more flexible approach that will allow you to attach different types of attachments to a message but for now let's keep it simple and let's go to our setup data to the message model and simply say that we will have an array of images I'm gonna start right away with array of images because it's gonna help us send both one image and multiple images at the same time so let's select here is array and yeah neither values are required nor the array itself is required so we can still send messages with our without images so after we we have done this uh change let's go ahead and save and deploy um and wait for for for our backend to update once again and after that is done we will be able to um upload images to the S3 and then link them with our message object in order to be able to query them later when we need it okay so can you please Implement status video call voice call in the next video um I I am planning I really want to do that I'm not sure if I'm gonna manage to do it like in the next weeks but maybe in December um by then like in December we're gonna do it so yeah I'm planning to add voice and video calling are you going to uh to be covering the status screen on this build uh actually I have never used the status screen in WhatsApp and I'm wondering what's so special about what's up about the status screen do you just yeah like what can someone explain me what's the point of status is in WhatsApp are we like stories or what oh yeah I think they are yeah to be honest I have never used it interesting we'll see we'll see if that's like an interesting feature we can um we can cover it in one video why not use typescript in order to keep it simple that's where the easy answer but yeah I highly recommend using typescript in all your production projects hi everyone did I miss to watch no we are just actually getting started we are uh in this video today today our plan is to add uh different types of attachments to our messages that we exchange in the application so we are going to be able by the end of this video we're going to be able to send uh to send images videos and exchange this information with users uh yeah like it's going to be interesting because we're gonna go for a lot of um steps like we're gonna implement it simply like with one image then we're gonna Implement like having multiple images then we're going to implement having videos as well and how to manage them and so on so it's going to be a very interesting um and insightful live stream foreign can we create application with nextges um yeah let me know if you're interested in uh net just next.js tutorials as well uh because yeah like uh I recently updated our blog platform to next.js13 and uh still like I'm interested to get to to get into more details about the new features from Nexus 13 as I didn't had like the proper time like to to analyze and study them properly but yeah like it's it's an interesting stuff it's I see it as a breakthrough for web development and if you guys are interested we can we can we can arrange something uh in future related to next just next GS as well come on deploying like one simple model one simple field and we have to wait so much and I think we're not able to move on to the next task yeah because my next Tasker is going to be uploading images to S3 so let's wait until all of these changes are done so that we can pull them updated backend in our application and then start uploading images to S3 all right so here we have it our application has been deployed and now we can copy this amplify pull command and come back in our terminal to pull the changes here uh [Music] what local changes detected hmm I'm wondering amplify okay let's try to pull it nonetheless foreign yeah like especially when you mess up like some small thing and you have to add it one more time so we see that uh we already have a new category here storage and that's good um what I want to check right now is if our graphql queries updated correctly for example I'm interested in the message if it has images and as you can see hmm let me check message message I need something um I'm gonna search for get message and as you can see here it doesn't have the images so that means that our graphql queries were were not updated so we can simply do amplify code gen to generate again like our graphql mutations and now if we're gonna check like one of this last message we see the images field and that means that the Alec it was updated as we did it in Cloud all right so um well yeah like we are done with the task one setting up a AWS storage we're done with task free to pick an image from the library because we saw that we already can select an image from the library we can deselect it and so on and now our task is to upload the image to S frame whenever we send the the message we need to upload firstly the image to S3 and then we need to um save the key to that file in the message in the message model that we are sending so let's have a look at what we will have to do we will need um we will need a library called uuid that will help us generate uh random file names so when we upload them images to one to the cloud we could keep the same file name as the user selected but that's a bit risky because if it is a very common username name of a file like if it's a that means that it can override other people images that we selected but in our case we're gonna override the name of a file with a random number it's not actually random it's um uh generated number that will be unique and that will ensure that all the files um are unique and nothing is overridden in our um Yeah in our backend in in the S3 now we should import this uuid function because we will need it a bit later to generate these names and where do we do that we do that in the input box so Source components input box index let's first import vcuid and make sure to import the react native get random values right above this in order to uh to to without this you're gonna have an error all right now um now we're gonna yeah like we're gonna start uh by taking this upload file function and this function will let me first put it here and when I'm gonna explain I'm gonna put it after the pick image and before the return statement in our input box um so we support file will receive a local URI and based on the local URI it will first like read this file it will transform it into a blob and after that using the storage dot put we're gonna upload this blob using a key but this key as you can see is the name of a file so the name of a file uh we generated using the unique ID dot PNG for example and lastly we are returning this key that we just generated for the file we are returning uh in order to be able to use it um later to save it into the database so uh what do we have to do with this upload file well we need to make sure to import storage uh module from AWS amplify so here after the authentication let's go ahead and import storage as well um what else do we need storage we have it yeah I think we have everything now let's go ahead and call this function where are we gonna call it and when are we gonna call it there is there there are different strategies to to use for this for example you should think when would you like to start uploading the image to uh to the S3 bucket when we after the user selected it or after the user press send there will be a couple of differences between these two options um and like there are pros and cons for both of them for example if you start uploading the image right away that means that when the user finishes his uh message the image will already be uploaded to S3 and well operation will be faster but at the same time if you start uploading it it finishes uploading and the user then decides not to send it you're gonna have to do some cleanup afterwards so in my case uh I'm gonna upload the image to S3 when I'm gonna try to save to send the image so when we press on send we create this new message object and then we should check if a user selected an image image then we want to um to assign to the new message you remember we added the images property the images property is an array and because we have only one image Let's uh upload it so we're gonna do a weight upload file and we're gonna send this image to be uploaded and because our upload file will like upload to the storage and then return the key We're Gonna Save in our database all the keys for the files that we are uploading there so with that being said yeah and um after we uploaded it we can reset it set image to null to get rid of it from here [Music] uh yeah let's let's see if it's gonna work let's open our terminal and let's make sure that we don't have no why did I stop the server let's make sure that we don't have any uh errors here and let's go ahead and try the first image send something happened we see the first image here in the message but we don't see the image well that's okay because we never updated them the message component that is rendering the message but let's go ahead in our amplify studio in the content and let's look at this message to see if it has a new image key so if we go to the content and we probably sort by image no oh this is chat room I'm looking at messages so if I look at the messages and I sort by images I will see this the latest one here with the text the first image and in the images we see a file let me copy this name and see where we can find this file actually the file we can go in the file browser also in amplify Studio that's why I like amplify Studio because it allows you to manage both the data to design the infrastructure and also to manage like files data users and so on from the file browser let's open our public directory and if I search this name I see that this is the only image in this directory and if I'm gonna download it download it or yeah actually we can see it right away here perfect that means that we uploaded the image correctly and we linked it to a message also correctly now let's open our components message index and here um before we are rendering the text let's render the image if it exists so if image exists we want to render the image but the problem is that I mean if message dot image exists we want to render them the image the problem is that a normal image component from react native it expects a full URL the thing is that our message dot image which our message dot image is an array of not URLs but to file keys so we just know the key of that file where is it we just know the key of a file and based on this key we need to uh to take it from the storage we need to create this URL one way one easy way is to use a pre-made component that we can import from AWS Rec native Adobe simplify react native and we can import an S3 image using this S3 image we can send the EMG key uh and it's gonna first download the image and then display it and then Style Styles dot image the thing is that the message doesn't have an image the message has images so if message.images dot length and is more than zero yeah that basically means if we have images attached and I should do it safely because images can also be null so if we have images attached here then we want to render one image and I'm gonna simply take it as message dot images at position zero this is going to be our image key the first item from our images array now in the image let's style this image here let me see if I prepare them yeah I have an image here let's simply copy them the styles and see if we're gonna actually see where even that so if I go here the first image and it is properly rendered right away perfect um now we can select images here we can add text and we can send them and they will appear here and they will be rendered properly that no the notion nodes are also in the asset bundle so when you will receive a email there you'll receive that link to the notion page foreign okay so now we saw a couple of things so far we have learned how to pick an image from the image Library then having that image file your image file URL like local URL we saw how we can upload this image to S3 using the storage module after that we based on the key of that S3 file we linked it to our new message here by seeing new messages images is these uh uploaded file and lastly when we query and when we render our messages we saw how we can render and directly an S3 image using their S3 image component that we import from AWS amplifier react native later on we're gonna see other ways of rendering the image but yeah like this is um easy and good way to to do it with without having to do extra steps so you simply send the image key and S3 will know how to download download and to display it okay so um now that means that S4 here is done and we can move on to displaying images full screen for that we're gonna use the react native image viewing Library so let's first of all start by installing it but you know what let me commit everything so you will have it uh let me foreign next task is to view images full screen as I said we're gonna use this react native image viewing so let's go ahead and copy the install command and paste it here in our terminal foreign so um if you open the documentation of this Rec native image viewing you're gonna see uh how how it works so basically what we have to do is to Simply render this image view component and by passing the property like visible or not visible we will be able to toggle um yeah like the visibility of the image view so what we're gonna do for every image that we are rendering here in the message for every image let's also render this property image View uh actually not for every image because if one message contains multiple image we will render only one uh image View component yeah for that um as you can see this image view expects an array of basically image sources which are Uris complete your rise to images the problem is that at the moment we are working with image Keys we are not working with image URLs so we're gonna have to take one more extra step in order to get the URLs of these images and then render them using uh them the image View so to download the images we're gonna need to do that in a use effect so use effect when are we gonna download the images whenever a message dot images change so if it changes then we're gonna we're gonna Define this fetch images let me check if it's the same name download images equal and async function and let's right away call it here download images now if message dot images is an actual array then we want to look for all of these images basically let me show you how it's done for only one of them so I'm gonna do if dot length is more than zero then we're gonna use also the storage dot get storage.get here in the storage.get we need to provide the key for the object that we want to receive and the key is going to be message dot images come on images at position zero uh I just want to show you what we're gonna receive by using the storage.get so console log URL now if I'm gonna check here uh a lot of things are happening possible and handle promise rejection which one storage can find variable storage yes let's go ahead and import the storage here in our message and now and now yes now I see this URL and this is the finger time console logging it's a very long URL but if I click on this and press open it's gonna open the image that I want to display there so that means that by using storage.get where is it by using storage.get and knowing the key of one item we can get the final URL and based on this URL we can already properly use like a normal react native image so let's do it like this we're gonna need a state variable for our uh for our image sources and set image sources use state uh it's going to be an empty array and here instead of console logging the URL let's do set image sources with a new array containing vcrl at this moment this will work only with one image but and we will have to come back to do a couple of changes um change to support array of images but now that's good so no actually we need uh we intend to save not directly the URL but uh sources and the sources is an array of objects where we have a URI property so I'm gonna rename this one URI as well in order to have it simplify like this now if I'm gonna do console log URI not URI but image sources we should see where if I open I see at the end that we have one image source with a URI and this property and um having this object with a URI as I said before we can move from an S3 image to a normal image where the source is gonna be our uh our image sources at position zero so will that work yes it works with a normal normal react native image but because we are saving them as urls that means that we will be able to render also the um the image View so the image view in our case it's gonna be somewhere here so for that we need to put our image in a yeah our image we will put it in a fragment because here we want to add the image View we need to import it firstly import image View from Expo image how is it called did they install it rack native image viewing yeah this one react native image viewing okay and what properties does it need it needs first of all it needs uh the images which expects an array of sources and because we already have an array of sources in our state we're gonna do image sources uh what else it needs the image index where it should start so we can start at position zero um it needs whoever is visible or not so visible equal true and now if I'm gonna go there I should see one of that images here not sure if it loads yes it loads and there is a close button but it doesn't do much at the moment because we need to provide here on request clothes which is a callback function that will be called when we press on that close button so for that we need a state variable to know if we need to display the image view or not so let's go ahead and image viewer visible and add a state here at the top const image viewer visible and set image viewer visible use State initially it's going to be false now for the visible field here in the image view let's do image viewer visible pretty sure what happened to you hope you are good and on request call we are gonna set image viewer visible tool back to false now let's see what's gonna happen now when we open this chat uh fail is notified yeah probably I need to reload it so if I go here no something is wrong you can find variable name oh at the top I must have used a wrong name here so it should be false um and now when we open we don't see the images opened but when I press on one of these also nothing happens because we are never setting the set image viewer visible to true and as I said when we want to do that when we press on one of these when when we press on the image so because our image doesn't have an on-press event or does it on price probably not that means that we will wrap our image with a pressable component let's put it here and add that on press we want to set image viewer visible to true now if I'm gonna press on this one it opens and I can close and I can open the other one as well so just like that we have like um full screen image viewer functionality in our application and later on it's gonna also work with multiple images because if one message has a lot of images we're gonna open it and we're gonna be able to swipe up for them okay so I hope you enjoy it you are enjoying it so far we still have a couple of features to implement today but if you learned something new today make sure to subscribe to the channel that will help us a lot to produce more and to produce more valuable tutorials in future how you doing guys um so far are you following along in the live chat guys uh all right so let's let's move on to the next step because the next step um yeah we are kind of done with this one so actually let me commit everything get add S5 full screen image okay perfect the next task the next task in our is working with multiple images yes [Music] so um sending multiple images from our backend side it's already it's already um yeah like ready because we have an array of images that we can attach to an uh to a message now we need to implement all these features from the front end in order to allow the users to select and send multiple images to do that let's go in our input box where we are launching our image Library and here we can send a new property allow multiple selection through and if we do that let's open our terminal here let me check if I need to foreign result I'm gonna leave it here image sources probably don't need it yeah that's it now let me clear it and let's um after adding this allows multiple selection and console logging the result let's go ahead and see what's happening here I'm gonna open the image selection and if I just choose an image the same is going to happen however if I'm gonna long press and select it I'm able to select multiple images and when I can press select and nothing happens because we're gonna see why here we see two console logs one of them when we selected one image and one of them when we selected multiple images as we can see the results are a bit different because when we select only one image we get back an object where we have this URI of the file however when we select multiple images instead of having like directly in the object the URI we rather have a an array of selected files and every selected file then is via the object with the URI so we need to in the result here when we want to set the image we need to check if result dot URI is defined or actually if result.selected is defined yeah if result.selected is defined then uh user selected multiple files else user selected just one file let's go ahead and update our State variable to be able to hold a raise an array of images not just one image for that I'm gonna simply change it to plural to make sense when I'm using it and I'm gonna default it to an empty array so I'm gonna move it to images set images and starting with an empty array now uh now yes we're gonna have to check where are we working with these images okay this is one place I'm gonna come back here uh here in the peak image where we are working let's finish here first so we want to set the images with let's go ahead and select them with result.selected here what we're gonna do is we're gonna do set images with an array where the item is the result so now um yeah at this moment like in the guide I'm still working with only your eyes not with a whole result object so we can actually do that as well uh as well now but later on we're gonna actually work with a whole object because we will need a little bit more information about that file but for now yeah like we need to save a result of URI and here we will have to map for all the assets and only get their asset dot I URI URI like this okay what else what else uh The Next Step let's scroll down let's scroll down a bit here so instead of checking if we have an image we're gonna check if our images array has more items than zero basically if it has some images then we want to render these two components for every single image in our array so let's go ahead here did we do it with a flat list Yeah we actually worked with a flat list so instead of rendering these things here because we have a list of images already uh we're gonna use a flat list a flat list that will work with the data images and when it will try to render something we will take the item which is one image URL and we're gonna render we're gonna render this too right both the image and the material icons yeah let's render here um let's start with an empty fragment and then let's put the image and the material icons for every single image here now I'm gonna update the source here to be the item that we receive it for every single render item execution style is going to be the same material icons on press when we try to remove one of this yeah let me actually do it in a moment just to see if everything is okay so far I'm gonna select one image and I want to see the same as we did before yes everything is good so far but if I'm gonna select more multiple images we're all gonna appear here uh that's good but I I think that I wanted a horizontal um flat list so I can send simply the horizontal property here and we see all the selected images here perfect I can also no that's okay now as I was talking let's see how we can remove one of these items before it was easy we simply set like our state with null but now uh we're gonna have to set images and we're gonna have to work with an array so let's send this uh to our Setter the update function where we will get the existing images and I want to do existing images dot filter I want to filter the image and keep only the ones that are not this item that I'm trying to remove right now so we set the images by filtering the item that we want to delete so now having three images if I'm gonna remove a one in the middle yes it works if I'm gonna remove this one and if I'm gonna remove this one yeah it works as well perfect and just like that we can select like really a lot of uh images you can work more like with how you render them like to display maybe some background um to to be better but by the end of the tutorial I think we're gonna come back and think about improving a bit the user the UI but we think the good thing is that now uh now it works uh and Lastly lastly we need to properly upload all the images because at the moment here we are checking if we have an image which we updated to images and now that's an array so let's check if images.length is more than zero um then new message images is going to be equal to hmm yeah we have an array of images and we need to call an async function upload file for every single image viewer so to do that we're gonna use some promise.all in order to run the execution like to upload images in parallel so firstly we need to Loop through every image there so let's do a images.map we will map for every image layer we want to do storage dot upload upload the image and remember that this storage.upload is an async function and we had to do a weight the trick that we're gonna do is we are not gonna await here rather we are gonna return the promise and because we are mapping for an array of images and for every single image we are returning One Promise that means that we are after executing this code we're gonna have an array of promises so if I'm gonna leave it like this it's not gonna work because we need to wait for every single promise in better way to be executed to do that we are gonna wrap them into that promise dot all and if you put an array of promises in the promise that all and then await that we will trigger like uploading um the uploading operation for every image then we're gonna wait until all the images in that array are uploaded and the result of the execution of the storage.upload but not storage.upload we have like uh upload file right sorry no sorry dot upload but upload file EMG file URI yes yes yes and as you can see because here our parameter from this Arrow function and the parameter to the function that we are calling are the same we actually can remove the arrow function and simply send the upload file here and now it's a bit more clean uh and set image not image but images to an empty array at the end okay let's see if it actually will work now let's select two images from here let's select them and let's go to images let's send and see if it works at the moment it simply it renders one image here and but if I'm gonna look in my word datum content message two images I see that our images array is an array of two keys that means that we have uploaded and saved our images correctly now let's go in ahead in our message component and in the message component instead of Simply rendering the first image we actually need to render all of them so so we should wrap this pressable that is one image actually I'm gonna do it a bit differently you know I don't know let's let's see uh let's start the way I plant it and we'll see if we need to to do something different or if that solution is okay so as I said like we don't have to render simply the first image we actually have to Loop through our image sources dot map and for every image source we have to render one of these pressables like this we need to render one of these pressables and also let's go ahead and change the the conditional here because it uses message.images when we need to do image sources.length um when we render the image we're gonna render specifically this one from that we are mapping over and now something should be working I don't know what but something should be working our Styles image was going on there image sources oh yes because here in the download images we are simply downloading only one image what we actually want is to download all of them so um we're gonna basically do the same trick as we did before using um using mapping and uh promise.all so you arise equal to we need to away the the promise of downloading all the images so promise.all then here we need to create their array of promises our array of promises is message dot images images dot map and for every image here we want to do storage.get like this storage.get EMG and I can actually remove this Arrow function all together now our URI is the array of Uris and I can send it directly here no this is an array of actually Uris but I need an array of an array of objects so your eyes dot map for every URI I'm gonna create an object with that URI key and field set image sources URI we don't need this one anymore and we see that the last message has two images here right away which um which is good and that means that we downloaded them correctly we can have a look at how we can better approach rendering them for example [Music] um one option would be to get the weave of our screen so with equal use window dimensions and let's define let's calculate the [Music] um the length of our container that displays these images and to do that look our whole container for the image has a maximum width of 80. 80 percent so const let me do it like this uh um let's do image container with equal to the width of the screen multiplied by 0.8 because we know that the parent component is 80 percent with uh uh but we also need to take into consideration that every container like basically every image has also some margin and some padding so 15 on one side and 15 on the other side I think it should be 30 so we need to do minus 30 here so now knowing where image container now knowing the image container then we can put our images hmm image View yeah we can put our images inside the view that will have the width that we just calculated Max or image container with this way whenever we have an image in the message we're gonna take the full space the full like we've that we that the container can take uh image container with now I'm also gonna assign some other styles to this container and our Styles will be called Styles dot images now let's go ahead and add some styles for our images container images container how did we do it image container so yeah what do we want to do basically I want to render when there are two images I want to render them side by side as two squares so for that we need instead of setting with to a specific like 200 value we need to set it to probably half of the parent component container uh or even less like to take into consideration like and if I do that we are 45 um and I can go ahead in my container that contains these images and I want to say that I want the flex direction to be raw I want them to be in the same row okay something happened but not exactly what we needed because we have a width of our image 45 we think is that our image is not the actual component that is uh a child of the image container of the images so for that reason we need to add some styles to our pressable that is the container of the image and we're gonna say that this is a style image container one image container so image container uh what we're gonna do is we're going to take the Wii from here to the image container and the height from the image also we don't need it there um yeah the image will simply have a flex one to take all the available space from the image container now the image container foreign we also need like actually we need the height for this image to to see it properly or if I do it here aspect ratio of 1 yes if I do aspect ratio one it will automatically set the height of this container to be the same as the width so we get like this nice uh squares if I'm gonna do 50 AFA will not be in the same row no actually we will be and if I do more will be yeah that's why I wanted to check if they are not overflowing um in order to make sure that when we don't have enough space to move from a new row and that's gonna happen when we add multiple images there then we can add a property to our images here a property called Flex wrap we want to wrap we want them to erupt from a new row yes and now if there is not enough space it's going to go from a new row and if I go back to width 50 that's still not going to be but no that will fit exactly how we want it but if I'm gonna add some padding 10 no it will work because padding is internal so 10 is too much but free is going to be good yes and border with I don't like it that much one not very good with designing today but it looks really nice at the moment as it is and the cool thing is that if I'm gonna open one of these images oh it's not gonna work or is it that one works this one works but this one doesn't why because we have pressable set image viewer visible hmm why you don't want to open there yes it opens and I can also uh swipe left to view the other image from the same message and yeah as you can see we can we can even send more of them [Music] let me select more of them select send and we should have actually yeah a lot of them in a grid and we're going to be able to see to scroll through all of them awesome another feature that you can Implement is to limit the number of pictures that you are displaying to probably four because that's what WhatsApp is doing so if there are more than four items the last one will be displayed with a label plus free more or plus 10 more in this way you limit like how many images you are rendering on the screen right away okay okay uh that's good but what happens with when I try to send one simple image if I try to send one simple image that image is gonna look like this basically it's gonna take half of a screen what I'm gonna do is in the style for our image container because image container is the component that has this with 50. I'm gonna actually check so I'm gonna add one more style here that will be conditional uh if image sources dot length is equal to one that means that it's only one picture and I want to if it's equal to one I want to render with to be 100 because it's only one picture no no it didn't work if image source is length I don't know let's do background color red if image sources is equal to one then do these otherwise do nothing uh still doesn't work image container image container if length I want to render this in a text here what's the length of the image sources nothing foreign image sources do I have a console log image sources foreign but it's still why it doesn't set the background for example Flex one oh image sources should be why it's image source and why I didn't complain about that okay I can remove a background and a weave and leave only this Flex one and actually I can also move back to that end operator because I don't need anything for the for the other part okay so now when there is only one image it's gonna be displayed full screen like this I mean full width of container and if we're gonna have more images we're gonna see them like this perfect so um I think we are we are done here I think we are done here uh and we can move on to to the next task we can view the images we can see them all perfect uh okay let me go ahead and commit everything git add git commit that's our s multiple images so it seems like an easy feature but it took us a bit of time to properly manage to implement everything from the UI perspective from the ux perspective now that that is done we can go back and see what is the next task and the next task is actually leading to uh towards being able to add videos as well not only photos and there are a couple of ways we can do that basically we can go in the data modeling and to our message the same way as we added images here we can add a new field that will contain videos and also will contain a list of strings the thing is that this approach might work okay when we have only images and videos but whenever we will try to add multiple types of attachments to um to our applications for example being able to attach an audio file being able to attach a PDF file or other things of attachments in that situation this approach of Simply Having like them separate here is not the best way to structure it and I want to introduce for this specific reason to be able to manage multiple attachments at the same time and different kind of attachments what I recommend doing is to actually add a new model that will store these attachments and it's going to be called attachment attachment how is it correctly attachment or attachment yeah I think it's like this so this attachment will have first of all it will have a storage key uh basically the yeah the storage key that will represent how to get it from our storage then it will definitely need a type we need to know is it an image or is it a video for the beginning for them type here we're gonna add the enum and let's create a new one and it's going to be called attachment type so we're gonna start with two types image and video and let's go ahead and save it this type is required and the storage key actually I'm not sure can we be um attachment type that doesn't have a file in the storage I'm thinking but I think that all of them should have so I'm gonna do it as required uh with type no the type it shouldn't be erased should be required yes all right what are our things um now that we introduce these attachments I really want to start saving more information about our attachments besides saving simply the URL I want to say for example for an image I want to say save the width and the height so let's add width and height and yeah this will allow us to properly render them like in their original um aspect ratio without distorting them it's also going to work for videos as well um but for the videos we also will be able to send the duration for example do ratio do ratio and the ratio or duration yeah with an duration that's also a integer and we're gonna save it in seconds probably or milliseconds and based on this field we will be able to display like how long is a video what else what else yeah I think that's everything uh here for the attachment now we need to think about their relationships uh what what is an attachment well an attachment is going to be related to a message because when we send a message we want to add a list of attachments here so for example when we send a message we want to add multiple images and this is the list of attachments so let's add them in a relationship to the attachment and we're gonna have a one message can have multiple attachments because we can attach multiple images videos and so on let's press save and that would be everything in order to manage like and send and query and display them but I would like to also add one more relationship I wouldn't I would want to easily query all them attachments all the basically pictures and videos from one chat room that will help us for example go into the settings here and see a list of images that were shared in this chat room so in order to easier query this information let's go ahead and find the chat room and see that we're gonna here is the chat room and say that we're gonna have a relationship with attachment where one chat room will contain multiple attachments by Saving this if I scroll down up to the attachment I see that it has already two more properties the message idea that will represent what message are we attaching this file to and we chat room idea that will say to what chat room and based on this like it's going to be help us query them all right let's press save and deploy and I think that we have everything there that we need foreign yes we are working um this project will cover both front discovering both the front and in the back end so in the first episode which you can find um in the description below there is links to all the episodes in the first episode we started with a user interface then in the second one we implemented the basic back end previous week we implemented um more advanced backend with sorting with real-time data with graphql subscriptions and also the groups feature now we are working on our storage and we will allow people to share uh photos and videos with each other so yes let's wait until our data is deployed and then we're gonna start working with attachments rather than directly saving them in an array in the message so um yeah while this is deploying uh I'm gonna take a short break and I'm gonna be right back here um so it's still being deployed foreign how do you allow users to select give images I can't seem to figure it out for that you would like you would probably have to use an API for gifs and one of them is this gifi and I wanted to to implement this as well so I really want to do basically everything but we are limited by the time so there is an API for this one so give me react native let's see if there is a react native SDK give your react native SDK not a lot of stars yeah so you would you would look either for something specifically for for rack native or you would interact with the API and do query the information like this iOS Android and web support react Android foreign native yeah this one is the library provided by gifty themself so it should be safe to use foreign like what components do we have like do we have some pre-made components dialogue give a dialogue but I think we should have like default default components that would make it really easy to to use oh yeah they offer pre-built templates which handle the entire Ty of GIF experience and grid only implementation which allows for Endless customization and we can use the Gippy dialog for the Plug and Play experience let's see if we're gonna have time by the end of a video like I'm gonna see if we we can Implement that as well now we are still waiting for our data model to be updated and we're gonna start implementing these attachments did they commit everything yes I did now we're gonna have to refactor a lot and that was my debate at the beginning whoever uh yeah let's let's go ahead and pull everything because it's ready and then we're gonna start refactoring and I'm gonna I was thinking whether to start with attachment right from the beginning but in that situation maybe it would be confusing for a lot of people and I decided to keep it simple even though we're gonna have to refactor now some of the things that we already implemented but it's going to be a very good experience because it emulates basically how you would Implement project yourself sometimes you implement a feature just for it to work and then when you have to add like other stuff like for example here we need to add videos we understand that probably is better to refactor to make it easier to work with different data so um after we pull everything let's also do amplify Cogen to generate our graphql queries okay we generated them and now uh what's gonna happen now what's gonna happen now let's open our probably components input box because the input box is creating and sending them the the messages and now instead of adding them instead of adding these images here to our new message the flow will change a bit the flow will be like this we first create the message then we basically save a message um we we send the mutation for creating the message and when we receive back with data we will have a message ID there and after that we will be able to create attachments because now now the attachments will uh reference one message and we basically need the idea of that message uh before creating them so what do we have to do in the input box in the input box yeah we're gonna in the input box should I foreign so let's do it like this so we have the onsend function we have a big image function I'm gonna yeah we have a upload file what we will add somewhere here is add attachment to message or just add attachment and what we're gonna add we're gonna add like basically a file and we will also need the message ID to know to what message basically we need to attach we also might need the chat room ID but we'll see how we will get it so add attachment for adding the attachment we first need to create new attachment is going to be equal to an object and then using graphql we're gonna do basically return API Dot graphql and we're going to run a graphql operation and what operation that create attachment touch meant create attachment but we need to import it from our graphql notations as create attachment like this is the same hopefully they are the same and for the variables we're gonna send the input the new attachment okay so um to find out about the input like basically what data do we need to send where we can basically have a look at the create attachment query or yeah let's let's go to our graphql queries or no mutation create attachment I can take these properties because these are the properties that we need to send so basically all of them except the ones that are Auto generated like created that updated that version deleted last change that and also by ID we don't need it so I'm gonna even take them like this so this should be our new attachment with data about the new attachment for the uh store range for the storage key we will receive the file URI and we basically can we basically can use the upload function upload upload file function that uploads a local file to storage and Returns the key we can call it here a weight upload file and we're gonna upload the file for the type we need to set like either image or either image let's start with simply image I need here a comma for the weave um I'm gonna start with zero only in a moment we're gonna see where do we get this information from message ID message ID is important because it's coming from here and actually I'm gonna replace it with capital D in order to have the same names as here and to to be able to use it like this and for the chat room ID if I'm not mistaken we do not have it here in the input box so we need to check where are we using the input box and that should be in our screens chat screen and if I scroll down we should find the input box here and we send the chat room that means that we have a chat from there so going back to them to the input box yes we have a chat room and that means that we will also have a chat from ID by accessing the chat room dot ID like that and yeah we need to make this function a sync foreign [Music] attachment that will create and save one attachment let's call it for every single image that we had selected for that we're gonna go in the onsand function after we created the new message data we want to basically because we have a more images we're gonna use the promise.all again and we need to map through our images and for every image we need to add attachment by passing the image and also the new message data basically we need to hear the message ID so to get the message ID we're gonna do new message data dot data dot the name of the operation create message dot ID if I'm not mistaking that's how it should be and lastly let's go ahead and console log here our new attachment just to see if we properly created with data that we expect and like it's important to console log it here to see if we don't have some undefined values because that's very common to have let's open up here and let's try to upload one image for example let's press next um let me find where I'm console logging console log new attachment I want here but image sources I don't need it here and yeah let's go back here and let's try again so uh this should be the new asset so it have it it has a proper chat room ID duration zero High zero that's okay it has a message ID which is not undefined that's what I wanted it has a storage key and yeah that's everything it needs at the moment um I'm thinking whether to show you how we we should uh render the image or how to properly set the width and height let's start by properly setting the width and height of our image and save them as an as invert attachment for that if we look above we have a console log and this console log is actually coming from the peak image function in the input box Peak image we are console logging the result and this result has this information that we need such as height such as with um such as type and so on so instead what I want to recommend is instead of only saving the Uris of our files in state let's save the whole object that will contain both a URI and also them metadata such as width and height and above here where we have set images we don't have to map we will simply save all the selected files there okay uh that's good result yes now uh another thing is um we can change the name from images to files we can start doing that because in a moment we're gonna start working with videos so it's better to have them consistent here because files will include both images and videos so let's do set files and I'm gonna search for images to see where we have it this one we already don't need it we need to create the attachments let's not to forget let's not forget to remove uh the files after we create the attachments not to have them selected there anymore now we have here images which is going to be our files and here we can do a file file let's search for the next image this one is a different set images No it should be set files and here set files moving on images.length it should be files.length and for the data it should be files when rendering it as I said we are not no longer saving arrays of URLs which we can send directly here but we are saving a raise of um file objects and that means that here we need to take the URI property of our item now let me check if we still have it set images here for when deleting it I'm gonna do set files existing files filter file file and item I think it's like this now let's try to add a couple of images select we're all added we're all rendered and I can also remove them perfect and I can also add only one yes that's good okay so um we refactor into files now when we are adding the attachment we receive here the file the file now this file is not going to be a URI but it's going to be an object with all the data about the file so when we try to upload the file we will want to upload the URI only not the whole object yeah we need the URI here basically now for the width we can take file dot with for the height we can take file.hide for the duration we can take file dot duration if it exists if it doesn't exist it's going to be okay and this image let's add to do videos as well to to make sure that we remember to come back here now let's try once again to add one file for example this one if I'm gonna send it we see that the duration is undefined because it's not a video the height is 1 1080. the width is 1920. it has a storage key it has a Type image basically it has everything that we need for an attachment now uh also as part of our refactoring effort is that we have to go into the message and [Music] um now we're not gonna work with message.images but we need to start working with attachments of our message first of all let's see if we actually will query and we'll get that data here so where are we getting the message from basically where we are rendering this message inside our screen chat screen we are rendering the message which is coming from this array of messages and if I check our set messages works with with the graphql operation list messages by chatroom so let's go ahead and we'll list messages by chantrum uh let's open this list messages by chat room and let's see it with data that we have right now as you can see at the moment we take the information about the item and we take some information about the attachments but we don't actually query the items that will give us the data about the attachments so in order to get this data together with the messages basically get the attachments together with the messages we're gonna have to copy this query list messages by chat room let's copy it from here let's go in our screens let's create a folder for our chat screen inside this folder let's go ahead and create a file chat screen dot queries or yeah like chat screen queries.js and here let's paste this query the next step is to move the actual chat screen file from here to our chat screen folder to have everything about the chat screen in the same folder it asks me to update the import so yes let's update it uh and also let's check in the navigation in the index how are we importing the chat screen we import from screen chat screen folder and we need to add here chat screen file okay let's see chat screen does it need some changes here to the assets for example the background messages we will not need it anymore and if I go here yes everything is working as it was working before but um yeah now we actually need to import our list messages by chat room not from our graphql queries but import these list messages not from here but from where this folder chat screen queries and if I go to the chat screen queries here we already can update this graphql query because in the graphql folder we shouldn't update it because it will be overridden every time we pull the backend what we want to do is to query information about the items information about the attachments so I'm gonna add the items object here and I'm gonna find like properly What fields does the attachment have like let me search it like this so here list attachments I can actually take weave together with items all of this information go to our screens chat screen query and instead of these items I'm gonna put items that I just copied in this way we are also getting like all of this information about them attachments for our message this was the first step and let's go ahead and let's let's console log here our messages console.log please do messages and let's see if it actually works so if I'm gonna go here console log messages in the chat screen I want to do actually console log Json stringify messages null and here tool let's just check if we are there why why I don't see the console log console log hello that's probably not updated um might be problems with Imports oh my God from the chat screen for example here so many things from the chat screen think it's correct this one should be correct hmm chat screen queries what's going on I can of course stop the server and start it again usually that helps hello Kamal how are you doing foreign up yes now it works and now it renders the images the messages and the cool thing is that the messages contain these attachments and most of them have items zero but the LA the first ones here they should actually have attachments and we see that this one has one attachment with storage key this one has also one attachment and so on so in our message component here instead of working with message.images basically everywhere we are working with message.images we should do we should work with message dot attachments dot items and this one probably should be no I think it should be like this so now it's not going to be download the images is going to be download at touch meant let's call download the attachments and if message dot attachments dot items dot length is more than zero than the uri's will be a wait promise again attachments dot items dot map but the way I did it so let's see for the yeah the way I did it is I basically I did the downloaded URL to all the attachments that I already had so I'm gonna go ahead and copy this use effect for downloading attachments and let's paste it here instead of hours what is doing here let me fix a bit the these small issues so what it's doing oh actually we should fix in a lot of places a touch immense a touch men's attachments make sure you don't have any typos as I did and yeah like here we are checking if we have attachments and if we have uh when we're gonna try to download every attachment file that we have so for that because we have an array of attachments we're gonna map through them and for every attachment we're gonna first get the file using storage.get in the storage key of that attachment and after that is done we're gonna simply add that URI to everything that we already have about the attachment so here we're simply adding one more field to every object in our array of attachments and then waiting for all of them to complete and finally setting them in them state so our state uh uh instead of image sources it should be already const downloaded attachments and set downloaded attachments you use state like this so let's see where we want to display them well we want to display them here instead of image sources we will check if download download attachments is more than zero then we're gonna Loop program and render them let's see if it actually works anything is not an object message attachment attachments attachments here I had one more mistake so now will you load image sources can find variable image sources let's see where do we still have image sources image sources yeah this one should be a touch download attachments downloaded should be ah I was gonna leave it like this again where so images should be whole images should be our basically download attachments because we have a URI I can simply do a mapping so that we only get the URI we only get the URI and we only return the URI without giving it like more than it needs so let's see let's see rendering it tell me that it works please not fully but why because image wants to render the image source but our image source now is a URI image source dot URI like this and it properly renders and if I press it renders it here as well and if I'm gonna send more attachments with my message I hope that I will see all of them and Let me refresh because at the moment it's not gonna update automatically with attachment and then what I'm gonna cover that in a moment so if I check here it's loading and I see all of them properly okay uh that's good I think that we are done with refactoring images to work as attachments now you can go ahead and from the data you can even remove the uh the from the message you can even remove their images because we don't need them anymore we are working with attachments for both images and videos in The Next Step we're gonna go ahead and Implement videos but before we do that uh give me one minute I'm gonna be right back yes I am back uh and we can continue can you implement status yes I read your message and I already answered that we're gonna try that not today and not sure if next week but I have it in my plans to continue this build with call and videos as well ah all right so what I wanted to check here is yeah basically this task is done for the attachments um where do we have some console logs in order to remove them now for example new attachment here I don't need it anymore result I don't need it anymore this one also we don't need it okay that's good let's add everything uh s 7 and touch men's perfect so by doing the images using attachments now it's going to be much easier for us to implement sharing videos as well so sharing videos we are gonna start first by going into our input box where is components our input boxes here and when we launch the image Library we want to be able to select multiple media types not only images we want to select videos as well so the first step is to add all here now let's have a look at what's going to happen if I'm gonna select a video well it's gonna display it kind of that that thing I was kinda surprised because this is an image this is a URL to an image we are rendering it into a simple this is a video it's a URL to a video we are simply rendering it into an image and it simply renders the first frame I thought that an image is not gonna render and video is not going to render in an image but actually it works so we are good on this side um now uh what else what else yeah before I actually try to send this I want to fix this thing when we add an attachment at the moment We Are Always setting that this is a image type what I want to do is to check if it's an actual image or a video our file that we selected we it has a type it has a type and it's going to be either image or it's going to be video in our case we want to map an image to an image with all caps and a video to a video and this is going to be our object um types basically is equal that is a very weird way of defining an object I don't know why I did it that way but I wanted it to be clear and probably I did it even worse but yeah like we have these object types and using the file.type we can map types file file command file DOT type so we will map from image or video to Capital image or video we also would be able to do file type dot to Capital capitalize but it's it's not going to be always like that so sometimes maybe the types will be different maybe we will have like a PDF I don't know like I think that this way it's gonna be more future proof all right so now that this is done I think we can give it a try and attach this video there so let me try to send this as a message with a video it's still loading it's still loading and when it disappeared which means that it loaded the attachment and if I'm gonna refresh let's see what we get well if I will go there we have a video we have a video about the video I'm not I don't think it's gonna render anything where it might render the the first frame after it's downloaded but probably it's not gonna be rendered and the thing is that we need a library to be able to play videos in our application we're gonna use the library from Expo called uh Expo AV that allows us to work with audio and video very nicely and for that let's go ahead and install it using npm Expo install Expo AV let's do that here I just joined RV stickers no these are these are images they are with only the images that I had here so okay now that we have that Expo video what we can do is to we can render a video based on its URI so let's copy this component from here let's go ahead in our message component index and when we try to render uh when we try to render uh an image here we need to check if our attachment download attachment dot map here should be attachment because it's gonna make more sense here should be attachment and we need to check this we want to render this image only if attachment DOT type is equal to image we want to render this one otherwise I'm gonna do it this way otherwise I want to render the wait a second where is it it's here too many parentheses otherwise I want to render a video So based on the attachment type I conditionally render either an image or a video sorry so we have here use native controls for the source is going to be attachment.uri that's correct should play we want to pause it for by default for width is going to be Max container with is it email it should be image container with not Max image container with and here as well image container with and we can go ahead and see if it actually works video is not defined yeah because we need to import a video import video from Expo AV Expo AV like this now if I'm gonna go here we see a video there it's posed but I can play this video and I can also make it full screen and I can play it and it actually it actually works oh it actually works so that's better we invest a success for us I'm thinking already for for the next steps um I'm thinking that at the moment like everything that is happening here uh with attachments to to be rendered with a message component it's a bit messy and not very future proof because at the moment we only can render two types of map of attachments but maybe in future we're gonna have like more types of message of of attachments so what I want to probably do not sure how good of am how easy it's going to be but I want to extract different attachment types to their own components so for example in the component message inside this message component I'm gonna create a new file for the image attachment TSX uh let's bring let's generate the empty component here react negative functional export and in the return statement here let's go ahead and render this pressable because this is about an image component let's go ahead and import pressable let's import image um uh image container it needs some Styles so I'm gonna copy all the styles from here I'm gonna bring them in the image attachment again I messed up the name I'm gonna leave it like this let's add the Styles and let's remove the ones that we don't need for example this one yeah images hmm maybe maybe like this we also need to make sure to import style from react native what else what else image attachment well this image view should also be there so I'm gonna cut it from here it should also be part of the image attachment but it should be kind of outside of our pressable so we're gonna have an empty fragment we're gonna have the image with a pressable first and then the image View this image View we need to import like this foreign it's gonna be oh it's gonna be a bit uh tough interesting because we need to handle in this image attachment we need to handle both the situation when we have only one image and when we have multiple images so how we're gonna do it It's tricky because I don't know how WhatsApp is actually doing when you have multiple types of attachments for example an image and a video let me try to see how that would look Photon video library and if I'm gonna send a video wait a second come on if I select this one and the video how it's gonna work foreign as two separate messages and only if I select multiple photos they are displayed as one select let's select one more the situation for me like WhatsApp always put them in in separate um in separate components but look look what uh I think that I'm gonna do so image attachment we're gonna receive here at touch men's um attachments yes and let's we need to map yes we need to map so we're gonna do attachments dot map for every for every attachment we want to render this pressable here we need to check if attachment length is one then it's going to be Flex one otherwise we need the state variable for them image viewer visible and the components is going to be called images image attachments attachments plural okay uh what's next what's next source is attachment dot you are right attachments that's good this is attachment s good um use State we need to import it from react like this what you don't like osts sex should be GS I don't know what what happened there all right so this is a component that will handle rendering one or multiple images so how we're gonna use it here well we don't need any more we don't need any more so look what I am thinking what I'm thinking I don't know to be honest so download attachments of course I can start it like this image container with style images I can start by doing image image attachments and I'm gonna send their download attachments so basically attachments equal download attachments and in this situation I'm not going to need this part of rendering the image I only need the rendering of video but this one I will keep it like this for a moment so what's going on here attachments I need to attachments let's go let's go let's go so this is an image component yes it works this one is video It Doesn't and it's not supposed to and this one are working as they were working before perfect now the same thing with uh with the video so we're gonna have a new file video attachments dot Js and here let's do Rec native function export and I'm gonna copy the the video from here let's render it here video what else do we need we need to import video from Expo AV image container with probably we're gonna receive a weave here and attachment right attachment and that attachment with with yes something like that now going back I am going to render here not a video but a video attachment for the attachment I'm gonna send this attachment and for the weave I'm gonna send image container with now will it work with the videos as well no because I'm looking for all of them here so what I can do actually is I can split my attachment in image image attachments equal download attachment dot filter attachment only if a type is equal to image and the same way I can filter video attachments video so in the first in the first one with image attachments I'm gonna send here only image attachments and here I'm gonna Loop through only video attachments but instead of looping here let's Loop inside the video attachments so let's simply send all the video attachments there and in the video attachments let's go ahead and do attachments which should be plural dot map and for every attachment foreign come on for every attachment I want to render this video and I think I have to put them into um empty fragment like this most probably they will also need a key and I'm gonna take simply that attachment dot ID for the key and let's do the same for the image in the pressable I'm gonna add key attachment ID now will it work video attachment Sage this one works this one works everything works um I'm gonna go back to the messages and look here at this so download attachment so if there is if there is attachments then render either images or video attachments yes foreign yes and now uh what's good about this is that our message component is a bit more lean meaning that it doesn't have to do the responsibility of every type of attachments it simply knows that it has some kind of attachments it knows how to render them but the low level logic of a different types of attachments are managed by every component uh separately and this will allow us to add later on like audio file attachments or PDF files attachments or audio like yeah I said already audio um gifs attachments and so on it's going to be much more easy to add new types of attachments we have a video attachment here yeah should be good foreign what's going to happen if I'm gonna have multiple videos or a video and two photos what's gonna happen then let's try and wonder what's how it's gonna look and now if I'm gonna refresh and if I'm gonna go here it works it displays the the images only only images here good and separately displays the video as well it works actually better than I expected okay um so we are done with these S8 videos we know we saw how we can add and send videos in the application so let's go ahead and add everything be it commit minus m S 8 videos and I want to show you a couple of things to improve a bit the user experience one of the problems that I want to showcase is the problem that when we send a message message with attachment uh when I send this message with attachment it is going to be sent but the attachment is going to be missing there it's not going to be there and why is this happening because we are listening in the screens chat screen chat screen as you can see here we are listening to new messages but a new message does not include its attachments a new message is simply yeah like contains information about them the message itself like with text and when it was posted but attachments are relationship to messages so what we can do here is we can subscribe to yeah it's a bit challenging and it's a bit tricky but my idea is to subscribe to new attachment events and filter based on this uh chat room ID basically receiving only them new attachments that are created for this chat room and then finding the message that it belongs to and attaching it there so um for that we have here subscribe new messages let's go ahead and add another subscription here for subscribe to new attachments subscription uh attachments let's make sure to unsubscribe here so for that we need to Define the body and do unsubscribe for this one as well um subscription attachments we're gonna do a graphql operation on create attachment on create attachment using the filter chat room ID equal to chat room ID and the filter is going to be the same so if I look at the oncreate attachment subscription the filter should have chat room ID so this is actually a new feature of amplify of being able to filter using your subscription and to subscribe only to the specific data that you need before it wasn't possible so we we actually announced it previous week so it's it's really nice to be able to to filter so filter subscribe next value let's go ahead and console log this value console log let's do new attachment and here let's console log the value itself so if I look here and if I'm gonna try to yeah let's try to send one hey let's try to send the message is there and we have new attachment data on create attachment and here is all the information about the attachment including the message ID based on this message ID we need to go ahead and find the message uh where the attachment belongs to so for that we're gonna actually use the set messages uh existing messages and we want to um to do what we want to find okay let's uh let let's open it up here and think so our our new attachment is on the value Dot if you remember correctly value.data dot oncreate attachment so value dot data dot oncreate attachment and new attachment has a message ID and we need to find the message based on vet ID Mass exists exists so const [Music] how to easier do that where's the question foreign let's try something so first I want to get the index of a message from existing messages Dot find where your existing message dot ID equal new attachment Dot message ID message ID like this hopefully so we're gonna find the index and then uh uh no this is actually the okay let's find the index and then uh using splice replace the item in our index with existing messages with with an object ex where we add to them existing messages and position index we add the attachments a touch attachments how how is the structure attachments Dot items oh my God it's so complicated I mean confusing so we need do attachments dot items and we will add here the new attachment who that was kind of complicated and probably not correct but let's see so if I'm gonna send a new file here yes anything is not an object level weighting existing messages at index existing messages existing existing existing messages index dot attachments but we need to check if foreign index so if index is more or equal than zero then now if index is equal to -1 that means that it didn't find anything so we can simply return existing messages otherwise we will update and add the new attachments there I hope I hope that it works so if I go here ABC send I didn't work properly I wonder why um now let's let's actually find the items so message to update equal existing messages find let's find then we're gonna check if we didn't find the message to update then we're gonna return them like this otherwise our message to update Dot attachments dot items dot push uh we're gonna push the new attachment but we should also check like if these items are not there if these items are not there and we need to take them safely then we need to add them there as an empty array and then we will push them and we will return what are we gonna return now this message to update we need to put it back into the existing messages so I'm gonna return existing messages dot map uh uh message uh if this message is the one that I want to update that ID then I will run I will return the message to update otherwise I will return the message from here will it work what's the logic there I don't know but hello I send hello and did you find the attachment did you attach it it doesn't seem too foreign something happened but I'm not sure if exactly what I needed foreign let me console log the first message console log messages at position 0. so this one has attachment items I need to stringify null and here two okay this is the last message it has attachment it has items but if I'm gonna send one this is the one it it has where this is the object it doesn't yet have attachments that's correct because we are we didn't edit them yet and after that attachments items correct it's the same structure items attachments items attachment items and why they are not updated let's go ahead in our message component index and here we have message attachment items probably didn't trigger an update console log I should we download or not hey we will see it a lot of times GS instead of TSX did I again uh made a TSX mistake foreign so what's happening here with our images I'm gonna send foreign why you're not downloading so what's happening here should we download download attachments um foreign foreign Jason stringify null and two and let me check where else I'm console logging this one doesn't give us a lot of things and this one it's gonna be too much for us let me go into um chat room with not a lot of attachments and let's try here attachments is empty foreign foreign but I think we're gonna get there you are right it actually has a URI but only one of them as you can see only one of them if it means that it doesn't trigger yes I think it doesn't trigger it here oh can't can't rub my head around this um um console log down loading attachments foreign attachments in empty [Music] and it's called only once downloading attachments empty but message is coming from here message attachments so messages it has with attachment everything good now if I'm gonna do one more messages is still this one I don't understand messages my head doesn't work anymore ah so I don't have any water that's bad um let me let me check this one no this is still the world one this is still a world one ah okay so messages doesn't have attachments when initially we added there correct but it has an ID then we have messages with attachments and we correctly added the attachments to the same ID E5 E5 we added attachments items D type and so on foreign this item goes here to the message and it should trigger this one but it doesn't message it doesn't because it would show downloading attachments it did it here but that was when we didn't have attachments the second time it didn't trigger it let's try again so we choose this picture we send it the first time it's not gonna have attachment then it's gonna have attachment but it's not downloading foreign so let's see what message prop do we receive here maybe something is wrong there so messages message prop it has attachment items empty yes downloading attachments okay then message props attachment item CS message prop again messages it now has items and here yes it has items but it doesn't download because this is an array so foreign foreign dependency because it's an array so stringify okay finally yes hello guys okay so finally I managed to do what I wanted to do and that was to listen to attachment updates and add it automatically here because we uh yeah like by adding a separate model for our attachments when we listen to updates to our messages that was not enough to update also the attachments so that's why we had to also ah the another listener here to subscribe to new attachments and to update the message with that if message the different items a key message on push yeah this function is probably over complicated and you can optimize it but after three hours my head is already not working uh I'm happy with how it turned out let me try to add two images and let's do hello and let's try to send it now it's gonna go hello and it's gonna add both images there and we can right away scroll through them I never figured it out myself yeah it was uh it was a bit weird uh uh I couldn't see that the dependencies and array and in the situation it's not checking every item in that array it's just checking is just comparing the reference to a race and the reference to the array Remains the Same we just add a new item so that's why um it does it is making me it was giving better now that we are stringifying it it will compare like the actual items as string so it's gonna know like properly when at least one of the items changes or we add new items there it's gonna start downloading them oh and there is actually one more thing that I wanted to um to try to do today uh I hope I'm not gonna regret this but uh here I'm talking about um displaying progress when things happen this is a very important topic in mobile applications whenever something takes longer than a couple of milliseconds then it's really good longer than a couple of seconds let's say when it's good to show some uh progress indicator to the user to let him know that you're actually working on something and his input was registered he doesn't have to press again he doesn't have to do anything he just has to wait one good example of displaying progress and this problem is when we're trying to send for example a video uh this is a video so I send the image I send the message the message actually is sent but it takes a couple of seconds until the video is also sent added so for that uh we need to probably add like some um loading indicator uh how are we gonna do that uh we're gonna go into this no screens components in the input box in the input box we have here upload file with the storage if we look in the documentation of the storage uh AWS amplify storage when we have a put put operation upload files here we will see that we can send some some callbacks for example we can have a progress callback and that will uh will be called here in the storage put uploaded this progress callback will be called every time there is no progress and we're gonna have like the total amount of bytes in the amount of buys that were successfully loaded so far so if I'm gonna try to upload the email video here we should see uploaded uploaded uploaded until it's done what consoles console logs do we have there console log Json stringify this one I don't need it anymore yeah everything good now so we're yeah here uploaded so as we can see the second one is the number of bytes uh the total number of bytes of a file in the first one is the uploaded number of bytes So based on these two properties we can save it somewhere um this property and display it on the screen as a loading indicator was a progress bar what do we want to do input box input box so upload file mm-hmm file URI I'm thinking what's gonna happen if we have more of them uh I'm thinking about the UI at the moment how to render this progress indication and I'm thinking that files flat list here with the image I will probably render I don't know a view on top I'm gonna be very Scrappy about it and I'm gonna do a text with percentages of how much it was 58 for example um so if I select one text is not defined I need to import it let's import from react native as text and I want this view to be position absolute I want it to be I don't know top 50 percent left 50 percent how it will look something okay like he's not perfectly in the center uh probably out is not gonna work I'm Gonna Keep it like this I'm gonna also add a background color RGB a I need a grayish color I don't know foreign I said I'm not gonna spend too much time and now I'm searching for colors so I want to add also some transparency there I want to add some padding like five I won't pour the radius 50. and now yes okay it doesn't really matter that much how the style of this indicator I just want to show you how you can do it in terms of logic yeah I'm already saying color text that with me something font wait it's okay it's okay now what I want to do is where we have these files what do we have here files uh item foreign I'm gonna simply have another array of progresses set progresses progress says use State it's going to be like this and when we update the progress upload file uh I want to set progresses to the item here I will need index as well so add attachment now come on come on come on come on think think um let's check Expo image picker I need to know if the image has some kind of an ID the response image info asset ID the unique ID that represents the peaked image or video If Peak from the library it can be used by actual to manage a peaked asset this might be null one by D is unavailable or the user gave limited permission that means that I'm not gonna work with this but I can work with them URI and have a URI um as is the key for our object so the progress is is not going to be an array it's going to be an object wherever key is the URI of a file and the value is the progress and this way we can simply set progress with uh existing progress and then we only want to override that we have here file URI and the value is going to be progress loaded divided by progress total something like this we need to put it into an and now here instead of 58 let's try to take progresses uh at position item dot URI will it work I don't know I'm afraid to think select now it doesn't have anything so I can do this or zero or let's only do let's only display it if it actually exists so if I simply select them nothing shows but if I press here right away but yeah the progress we need to multiply it with 100 100 because uh dividing the number of bytes loaded by the number of by the total number of bytes is going to give us a number from zero to one so that's why we need to multiply it by 100 and then we should also do math Dot foreign do T to fixed actually zero just yeah and now and this one select if I do what okay 100 and this one yes it works so now it's much better because if you select a big file and you start uploading it you will see that it starts uploading so you're not going to do anything else you're gonna wait until the file finishes uploading I don't know why it stopped for me but it should be should be fine yeah maybe I happen with my emulator okay so if I'm gonna try to send this one more time it's gonna start 70 90 98 100 and that's it so this way we can display progress uh based on web progress callback that we get from a storage this is very useful use it as much as you can to provide like user feedback of how long it will take because for you it might take one to two seconds but not everyone has a fast internet and for some people it can take a long time and the worst thing is if a user will not know that everything is working fine and he will wait for a minute and then he'll close the application and you will have a partially uploaded file all right so and the same thing with um with displaying loading progress and activity indicators would be true and I would recommend for you to do the same when you load images because when you will open a page it's gonna start with empty and then it's gonna start loading these images because we already know data we already know for example in our content in our content attachments because we already know the width and the height of images that we're sharing you can basically without having to download the image you can know what's going to be the basically the height and the width of the image that is going to be uploaded later and you can render a view with that sizes and with an activity indicator in the middle and that will prevent all of these layout changes that we have at the moment so that's going to be uh vet's going to be your homework and actually I'm gonna add it here homework uh s nine um so uh to do add activity indicator indicators for images for attachments um render them images to be loaded with their true with their size to avoid layout shift then a very good feature that we haven't implemented today is managing your profile picture profile picture we saw we learned how to work with images we learned how to upload images how to update some messages to an add an image so your homework would be to do the same for profile picture for for that you of course will have to add a couple of user interface I mean some some screens but the logic of um uploading and adding a image you can take inspiration from what we did today and I'm gonna try to add more things that you can improve on um with the storage here um I'm gonna go ahead and do git add git commit minus m and refactoring yeah and I'm gonna go ahead and push everything to origin and if you follow the link in the description below of the source code you're gonna have access to everything that we have built today all right guys um thank you very much for being here with me till the end while I'm recording thank you yeah thank you very much for being here with me till the end I'm super tired but I'm super happy with everything that we managed to build today so today we learned a lot about how to work with media how to work with images how to work with videos how to upload them store them in Cloud link them together in order to have uh features like media like sharing images and videos in our chat applications I hope you enjoy it if you enjoy it make sure to subscribe to the channel drop a like and um yeah turn on the notification Bell not to miss our weekly Friday live streams uh next week we most probably will continue this uh build because I'm very excited about this and I want to take it even further from here and add more features for that I need your help let me know in the comments what other features you'd like us to build uh in the next episodes and we will take into consideration and we'll try to um to build features that you want to to see in this application with that being said uh it was a nice week it was a nice live stream bye guys have any haven't
Info
Channel: notJustā€¤dev
Views: 86,338
Rating: undefined out of 5
Keywords: vadim savin, not just development, notjust.dev, react-native tutorial, react native ui design, react expo, react native live coding, live coding, react native aws amplify auth, react native auth, javascript, react tutorial, whatsapp clone, build a whatsapp clone, whatsapp clone react native, whatsapp clone tutorial, aws amplify, chat app, react native, react native tutorial, javascript tutorial, real time chat app, socket io, programming, react native chat app
Id: pqQGU-JsD7k
Channel Id: undefined
Length: 205min 54sec (12354 seconds)
Published: Sat Nov 05 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.