How to create a private image upload using Appwrite and Flutter
Tags: appwrite, flutter, imageupload, appdevelopment
Published: 2022-12-29 10:06:39

Public image libraries such as Unsplash have been a breath of fresh air for content creators, enabling access to tons of copyright-free images. Sometimes, though, creators prefer privacy content and want to gatekeep "good" things.  This article covers how to securely upload private images to [Appwrite](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog) using Flutter.

This article demonstrates the following:

- User registration and login using Appwrite
- State management using the provider package in Flutter
- Picking images from storage using the `file_picker` package in Flutter and uploading the images to Appwrite
- Setting document-level permission within Appwrite
- Obtaining the images from Appwrite and updating the UI

If you want to jump straight into the project, you can clone the [repository](https://github.com/muyiwexy/private_upload) containing the code for the project.

## Prerequisites

The following requirements apply to follow along:

- [Xcode](https://developer.apple.com/xcode/) (with developer account for Mac users).
- Either [i](https://developer.apple.com/documentation/xcode/running-your-app-in-the-simulator-or-on-a-device)[OS Simulator](https://developer.apple.com/documentation/xcode/running-your-app-in-the-simulator-or-on-a-device), [Android Studio](https://developer.android.com/studio), or [Chrome web browser](https://support.google.com/chrome/answer/95346?hl=en-GB&co=GENIE.Platform%3DDesktop) — to run your application.
- Docker installation (recommended), [DigitalOcean droplet](https://marketplace.digitalocean.com/apps/appwrite), or [Gitpod](https://gitpod.io/#https://github.com/appwrite/integration-for-gitpod).
- An Appwrite instance. Check out this [article](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9) for the setup.
- The user interfaces template. [Here](https://github.com/muyiwexy/private_upload/tree/login) is a link to the repository containing the UI template.


## Setting up the Appwrite project

After setting up an Appwrite instance, head to your browser and type in your `IP address` or `hostname`. Next, select `Create Project` and fill in your desired `project name` and `ID`.


> Note:   ID can be auto-generated

![create project](https://paper-attachments.dropboxusercontent.com/s_4790BCE1D9901C61F6383518FE2D7DBEBF0E98C8364362B60F9C8BCE4293E832_1680803279297_Screenshot+287.png)


After creating a project, scroll down within the Appwrite console and select `create platform`. When you get a popup, select `Flutter` and choose the operating system you plan to work on 
(in this case, choose `Android`). Next, specify the `application` and `package names` (you can find the packaging in your app-level `build.gradle` file).


![Create platform](https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675132261190_Screenshot+259.png)
![Create platform](https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675132261213_Screenshot+260.png)


After creating a platform, head to storage to create a bucket. To do that, click on `add bucket`, then set the bucket-level permission's read and write access to allow all users (`role:all`).


![create bucket 1](https://paper-attachments.dropboxusercontent.com/s_4790BCE1D9901C61F6383518FE2D7DBEBF0E98C8364362B60F9C8BCE4293E832_1680803611326_Screenshot+291.png)
![create bucket 2](https://paper-attachments.dropboxusercontent.com/s_4790BCE1D9901C61F6383518FE2D7DBEBF0E98C8364362B60F9C8BCE4293E832_1680803611170_Screenshot+292.png)
![create bucket 3](https://paper-attachments.dropboxusercontent.com/s_4790BCE1D9901C61F6383518FE2D7DBEBF0E98C8364362B60F9C8BCE4293E832_1680803611229_Screenshot+293.png)



Unlike the other client-side SDKs, the Flutter SDK does not return a URL when previewing a storage file from Appwrite. In this tutorial, you will use a database to store the URL of every new image file upload. Head to the database section and select `create database`.


![Create database](https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675133088225_Screenshot+262.png)

Next, we’ll create a collection. When allowing public access to a collection, use collection-level permissions, preferably the permission `role:all`. In this case, use document-level permission, as this allows all the users to share a single collection, but they have access to their documents only. Now, let’s create a required string attribute called `url` to store the manually generated URL of each image added to the storage.


![Create collection](https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675133157888_Screenshot+263.png)
![collection permission](https://paper-attachments.dropboxusercontent.com/s_4790BCE1D9901C61F6383518FE2D7DBEBF0E98C8364362B60F9C8BCE4293E832_1680803957277_Screenshot+294.png)



## Cloning the Flutter UI template and connecting to Appwrite

This section uses a UI template containing user registration and login code. To get it, clone the [repository](https://github.com/muyiwexy/private_upload/tree/login) specified in the prerequisites. Check out the official GitHub [docs](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) to learn more about cloning a repository.

![cloning repo](https://paper-attachments.dropboxusercontent.com/s_4790BCE1D9901C61F6383518FE2D7DBEBF0E98C8364362B60F9C8BCE4293E832_1670224372635_7aAkFZ2g.png)
![cloning repo](https://paper-attachments.dropboxusercontent.com/s_4790BCE1D9901C61F6383518FE2D7DBEBF0E98C8364362B60F9C8BCE4293E832_1670224398326_fR9HnIBw.png)


If you're not new to Appwrite, you can proceed to the next step, but for new readers, this is how to connect a Flutter project to Appwrite for Android and iOS devices.

**i****OS**
First, obtain the `bundle ID` by going to the `project.pbxproj` file (`ios > Runner.xcodeproj > project.pbxproj`) and searching for the `PRODUCT_BUNDLE_IDENTIFIER`.

Now, head to the `Runner.xcworkspace` folder in the applications iOS folder in the project directory on [Xcode](https://developer.apple.com/xcode/). To select the runner target, choose the Runner project in the Xcode project navigator and then find the `Runner target`. Next, select `General and IOS 11.0` in the deployment info section as the target.

**Android**
To do this, copy the XML script below and paste it below the activity tag in the `Androidmanifest.xml` file (to find this file, head to `android > app > src > main`).


{% embed https://gist.github.com/muyiwexy/f1a0f6c59329d25d37c353f34a4fa9aa %}


> Note: change [PROJECT-ID] to the ID you used when creating the Appwrite project


## Getting Started

When you run the cloned repo, you should have a UI that looks like the image below:

![Cloned repo UI](https://paper-attachments.dropboxusercontent.com/s_4790BCE1D9901C61F6383518FE2D7DBEBF0E98C8364362B60F9C8BCE4293E832_1669735792157_Screenshot+116.png)


Above is a homepage section with an elevated button that satisfies multiple commands depending on the condition. These conditions range from checking if a user is logged in and redirecting you to a login page if `false` to selecting an image(s) from your local storage, uploading it to Appwrite, and displaying the images in a grid.

Currently, the template lacks most of the functionality mentioned above. Thus, start by updating two folders (constants and model) within the lib folder with some new files. Starting with the constants folder, create a file called `app_constants.dart`, which is required to store some constants that you will use later. Start by pasting the code below into the file:


{% embed https://gist.github.com/muyiwexy/c30259a4818fa4ccdb8df9c518e6f189 %}


**Image** **u****pload**
Next, we’ll create two model classes similar to the one in the template folder. Let’s use the first model class to map out the structure of the storage bucket, as we’ll manually create a URL. Thus, there are two essential data from every newly uploaded file: the `bucketID` and the `uploaded file's ID`.


{% embed https://gist.github.com/muyiwexy/3aac424cb808b2cefeaf5ce829224ac9 %}


To use the model class above, we need to be able to pick a file from your local storage and upload it to Appwrite. Thus, head to the `privateprovider.dart` file and call the Appwrite `storage API`, the model class created earlier, and a `PlatformFile` class from the `file_picker` package within the `ChangeNotifier` class.


{% embed https://gist.github.com/muyiwexy/359735e978c33090e614ac0e29f10130 %}


Next, create a getter for the model class, then set the value for the model class and the `PlatformFile` class to null(initializers). Also, remember to initialize the Appwrite's storage API. Next, create a function to select images from local storage and call it within the conditional statement in the `checklogin` function.


{% embed https://gist.github.com/muyiwexy/b614ef1473417d1f4d20c33af4577c32 %}


Next, create a function to upload the selected file from the local storage to the Appwrite storage bucket. In the function, we’ll need to map the `JSON` result to the model class using the `jsonEncode` and `jsonDecode` functions provided by the `dart convert` package. Finally, call the function within the `filepicker` function, and it should look like this:


{% embed https://gist.github.com/muyiwexy/f133821200bb3c75f2ceeb5079d6a403 %}


**Image retrieval**
To retrieve the images from the storage bucket, we need to use the database created earlier and create another model class to map the list of documents from the database. Thus, a model class like the one below is required:


{% embed https://gist.github.com/muyiwexy/b7526189b324d0c3839dbe964216a910 %}

Next, call the Appwrite database API and the model class above. Then, create a getter for the model class and initialize the database API.


{% embed https://gist.github.com/muyiwexy/aaf425a145eb51abae12395b68d43d67 %}

After uploading the image to a storage bucket, we’ll  "convert" the image into a URL. To do that, create another function, and within the function, create a variable with the value of a `query string` created from using the endpoint, `bucketid`, `fileid`, and `projectid`. Next, initialize the Appwrite database `createDocument` method and set the data to the variable you created. Call the function in the file picker function so it can trigger the function automatically after uploading the files to the storage bucket.


{% embed https://gist.github.com/muyiwexy/d237b8abe7141b95c727da451ecedfa1
 %}


Now, we’ll create another function to display the images using the `listDocuments` method from the database function. Then map through the list of documents with respect to the model class created earlier. For this section, we need to be able to display the images once a user logs in or once they upload a new image. Thus, call the function in the `_init`, `login`, and `createdocument` functions.


{% embed https://gist.github.com/muyiwexy/3cc3c21a9046c5d6ab1b69f9fa2a0180
 %}


Now, the provider is ready for use, and all that is left is updating the `home.dart` file with the code below:


{% embed https://gist.github.com/muyiwexy/fc62730cfc05510db5ef274abee64e98 %}

The code above consists of a button that triggers a function linked to the `checklogin` function within the `ChangeNotifier` class (`PrivateProvider`). The body uses a `GridView.builder`, which creates a grid of containers with respect to the number of items in a list. In this case, it is the list of documents in the database. The containers are decorated using a `NetworkImage` using the URL value obtained from the database collection.

![result](https://paper-attachments.dropboxusercontent.com/s_4790BCE1D9901C61F6383518FE2D7DBEBF0E98C8364362B60F9C8BCE4293E832_1669761381382_ezgif.com-gif-maker+9.gif)



## Conclusion

This article explains how to use the [Appwrite](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog) service to register and log in users as well as how to create document-level access to allow users to have permission to access documents particular to them alone. Using that idea, we’ve built a private image upload using the `filepicker` package and Appwrite.

For further reading, here is a resource you might find helpful:

- [How to upload images in Flutter using Appwrite](https://dev.to/hackmamba/how-to-upload-images-in-flutter-using-appwrite-2ekj)