Tracking medication dosages made easy with Appwrite’s database
Tags: appwrite, flutter, softwaredevelopment, hackmamba
Published: 2023-04-06 14:55:53

# Tracking medication dosages made easy with Appwrite’s database
Tracking medication dosages is essential for checking the compliance and consistency level in the prescription given by medical personnel (doctors, pharmacists, etc.). Likewise, it’s crucial for patients’ recovery from the illness or medical condition it was prescribed to treat. Appwrite’s database makes creating an efficient database system to track medication dosages easy.

By the end of this tutorial, we will have created a fully functional database system for tracking medication dosages.

Here is the GitHub [repository](https://github.com/muyiwexy/medication_history_tracker) containing all the code.


## Prerequisites

This tutorial requires the reader to satisfy the following:

- [Xcode](https://developer.apple.com/xcode/) (with developer account for Mac users).
- iOS Simulator, Android Studio, or Chrome web browser to run the application.
- An Appwrite instance running on either Docker, [DigitalOcean droplet](https://marketplace.digitalocean.com/apps/appwrite), or [Gitpod](https://gitpod.io/#https://github.com/appwrite/integration-for-gitpod). Check out this [article](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9) for the setup.


## Setting up the Appwrite project

In this section, we’ll set up an Appwrite project and create a platform. Let’s start by doing the following:

- Open your browser and enter the `IP address or hostname`.
- Choose `Create Project` option and fill in the `project name and ID`. (ID can be automatically generated.)
![create project](https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675132209657_Screenshot+258.png)
![create project  2](https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675132209708_Screenshot+257.png)



- Next, head to the databases section, select the `Create Database` option, and fill in the desired database name and ID.
![create database](https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675133088225_Screenshot+262.png)

- Next, we will need to create two collections within the database. The first collection will hold the medication data. Thus, we will create eight attributes: four Boolean (`isTrack``, isInjection``,` `isTablet, isSyrup`), three strings (`medicationname, userID``, i``d`), and one integer (`dosages`). This collection will hold the medication information.


    The second collection will hold the scheduled medications. Thus, we will need four string attributes (`date, medicationname, userID, id`) and a single Boolean attribute (`isTrack`). 


![create collection](https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675133157888_Screenshot+263.png)

    
- Finally, set the collection level `CRUD` permission for both collections to `Any` and select all the options.
![collection permission](https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675133182874_Screenshot+264.png)
![collection permission](https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675133218819_Screenshot+265.png)

## Getting started

In this section, we will clone a Flutter UI template, connect our Flutter app to Appwrite, and explain the functionality of our project. 

**Clone the UI template**
This section uses a UI template containing user registration and login code. Let’s clone the [repository](https://github.com/muyiwexy/medication_history_tracker) 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.

![clone app](https://paper-attachments.dropboxusercontent.com/s_4790BCE1D9901C61F6383518FE2D7DBEBF0E98C8364362B60F9C8BCE4293E832_1670224372635_7aAkFZ2g.png)
![clone app 2](https://paper-attachments.dropboxusercontent.com/s_4790BCE1D9901C61F6383518FE2D7DBEBF0E98C8364362B60F9C8BCE4293E832_1670224398326_fR9HnIBw.png)


After cloning the UI to local storage, open it in your preferred code editor and run the command below:


```javascript
flutter pub get
```

This command obtains all the dependencies listed in the `pubspec.yaml` file in the current working directory and their transitive dependencies. Next, run the command `flutter run`, and our application should look like the gif below:


![clone result 1](https://paper-attachments.dropboxusercontent.com/s_973FE6248EEDD7529E7A11435E297ADACD4E1B7483EB53A8303EEED9486C6A4E_1677497369211_ezgif.com-video-to-gif+3.gif)

![clone result 2](https://paper-attachments.dropboxusercontent.com/s_973FE6248EEDD7529E7A11435E297ADACD4E1B7483EB53A8303EEED9486C6A4E_1677497337804_ezgif.com-video-to-gif+2.gif)
![clone result 3](https://paper-attachments.dropboxusercontent.com/s_973FE6248EEDD7529E7A11435E297ADACD4E1B7483EB53A8303EEED9486C6A4E_1677497383478_ezgif.com-video-to-gif+1.gif)


The gif above shows the UI and functionality of the medication tracker, in which there is a section to add medication and track medication (overdue medication and currently tracking). These functionalities were achieved using Appwrite and `Flutter_local_notification` package.


> Note: This program doesn’t use the Appwrite real-time API. Thus, check the resources section for references to its use.

The following sections provide a breakdown of how to implement the features shown above. Let’s start by showing how to connect Appwrite to a Flutter application and seed data to the Appwrite database collection.

**Installing and** **c****onnecting Appwrite to Flutter**
First, install the `Appwrite`, `Flutter_local_notification``,` and the `Provider` package for state management into the app. We can add them to the dependencies section of the `pubspec.yaml` file, like the image below:


![pubspec.yaml](https://paper-attachments.dropboxusercontent.com/s_041BDED8DAB440A4B6CCF96EB23FFFC68E40117CE3B40D930FE7EEC37F7160D4_1675028904318_Screenshot+65.png)



Alternatively, we can use a terminal by typing the command below:


```javascript
flutter pub add appwrite

# and

flutter pub add Provider

# and

flutter pub add flutter_local_notifications
```

Here’s how to connect a Flutter project to Appwrite for Android and iOS devices.

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

Next, head to the `Runner.xcworkspace` folder in the application’s 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 find the `Runner target`. Next, select `General and IOS 11.0` in the deployment info section as the target.


![ios](https://paper-attachments.dropboxusercontent.com/s_973FE6248EEDD7529E7A11435E297ADACD4E1B7483EB53A8303EEED9486C6A4E_1677590542497_file.jpeg)


**Android**
For Android, 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.

We will also need to set up a platform within the Appwrite console. Follow the steps below to do so.


- Within the Appwrite console, select `Create Platform` and choose `Flutter` for the platform type.
- Specify the operating system: in this case, Android.
- Finally, provide the application and package names (found in the app-level `build.gradle` file).


![create platform 1](https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675132261190_Screenshot+259.png)
![create platform 2](https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675132261213_Screenshot+260.png)
![create platform 3](https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675132261236_Screenshot+255.png)


**Creating the** **p****roviders**
Since we will use the provider package for state management, here are the `changeNotifier` classes to be utilized:

1. **UserRegProvider**
{% embed https://gist.github.com/muyiwexy/e04941c12fada2b445ab3e7771262dad
 %}

2. **AppProvider class**
{% embed https://gist.github.com/muyiwexy/b3f79d1b111af77abcfb072da017f265
 %}

3. **ReminderProvider**
{% embed https://gist.github.com/muyiwexy/d8094e2a2eccc123d23822d501c8d00b
 %}

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

We used queries for the `userID` in the lists in case there is a need to add a super admin who will have access to all the items in the list. Also, we queried the `isTrack` attribute in the `ReminderProvider` to segregate the currently tracked processes to prevent a rerun in the instance when we run our program again.

Lastly, using JSON serialization, we can map the list of documents from Appwrite to a class and get our items in a list. Thus, we have created three model classes for each `ChangeNotifier` class.

Next, let’s head to the `app_constants.dart` file to store important constants within a class, such as the `projectID`, `database`, `collection ID,` and so on.


```javascript
class Appconstants {
  static const String projectid = "<projectID>";
  static const String endpoint = "<Hostname or IP address>";
  static const String dbID = "<database ID>";
  static const String collectionID = "<collection ID 1>";
  static const String collectionID2 = "<Collection ID 2>";
}
```

**Adding** **m****edication details**
This project uses three Notifier classes — `UserRegProvider`, `AppProvider`, `ReminderProvider` — to map out the user registration, medication document, and reminder document object. Thus, declare the `MultiProvider` class inside the `runApp` function of the `main.dart` file. This `MultiProvider` class will assist us in building a tree of providers like this:

```javascript
void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MultiProvider(
    providers: [
      ChangeNotifierProvider(
        create: (context) => UserRegProvider(),
        lazy: false,
      ),
      ChangeNotifierProvider(
        create: (context) => AppProvider(),
        lazy: false,
      ),
      ChangeNotifierProvider(
        create: (context) => ReminderProvider(),
        lazy: false,
      ),
    ],
    child: const MyApp(),
  ));
}
```

This allows us to use methods, setters, and getters from the provider classes around our project via the `Consumer` widget or by calling the provider class. First, use the `routerclass.dart` to create navigation routes between the `Add Medication Information` and `Track Medication information` pages. 

Thus, in the `Add Medication Information` page (`register_medication.dart` file), we have a `stateful` widget in which the body property of the `scaffold` widget takes a condition. This condition checks whether `state1` (`UserRegProvider`) via the consumer is true; it should show a `circularloader` widget, and if it is false, it should show the `appcontainer` widget.  This condition is to prevent the UI from loading before the provider. If that happens, we will get a null error, as some UI properties vary depending on the provider.

The `appcontainer` widget contains a column of the logged-in username (retrieved from the `UserRegProvider` class) and a form field consisting of a string text field, integer text field checkboxes, and a submit button. We can add the medication information to our database collection created earlier with this form field, and its implementation is in the `[**medicine_details.dart**](https://gist.github.com/muyiwexy/5d6b638092d6472d39423f807ca09010)` file.

**Tracking the** **m****edication**
To track the medication, we will use the Appwrite database collection to track our medication by attaching a Boolean value to each tracked medication. We will then use the `flutter_local_notifications` package to schedule a notification for each tracked medication.

Thus, in the `Track Medication Information` page (`track_medication.dart` file), we have a column of a button and a list area (divided into a row of Overdue and Currently tracking). When we click the button, it shows an `alertdialog` containing a checklist of all the medications. This checklist allows checking only one item at a time, and once we check an item, it shows a dropdown list to select the date form field to schedule the medication.

If a date or time before the current date is added, and we click done, then the item will be added to the overdue section. However, if a date is after the current date, then it will run the notification function. 


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

The done button triggers the `_notificationService.scheduleNotifications();` while passing `context, widget.reminderstate.reminderitem!` as parameters. These parameters will assist in building the notification function. Here is the code for the notification function:


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

The code above defines a `NotificationService` class that handles scheduling and canceling local notifications using `FlutterLocalNotificationsPlugin`. The `NotificationService` class follows the singleton pattern, ensuring that only one class instance can exist simultaneously.

Next, we create the `init()` method to initialize the `FlutterLocalNotificationsPlugin`, which is required before scheduling any notifications. The `scheduleNotifications()` method schedules notifications for a list of `reminders` (the parameter passed earlier). It converts the scheduled time of each reminder to the local time zone and schedules a notification using `flutterLocalNotificationsPlugin.zonedSchedule()`.

Lastly, the `cancelNotifications()` method cancels a previously scheduled notification using `flutterLocalNotificationsPlugin.cancel()`.
 
So, to use this code properly, we will need to call the `init()` method in the `void main` function, like so:

```javascript
void main() {
  WidgetsFlutterBinding.ensureInitialized();
  NotificationService().init();
  // add runapp method
}
```

The earlier results were on a web platform, and `flutter_local_notifications` does not support the web yet. So here, for the moment of truth:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zveh0qa2rae529llgs3o.gif)


## Conclusion

Taking medications isn’t the most pleasant task of the day, but failing to do so can pose a risk to a patient and cause problems for their caregivers or healthcare providers. Thus, a scheduler can come in handy, as we can now set a future time and receive a notification when it is time. The Appwrite database assists in sorting out those lists, and with a package like the `flutter_local_notifications`, we are guaranteed to follow our medication schedule.

Check out these additional resources that might be helpful:

- [Appwrite official documentation.](https://appwrite.io/docs?utm_source=hackmamba&utm_medium=hackmamba-blog)
- [Appwrite Flutter SDK.](https://appwrite.io/docs/getting-started-for-flutter?utm_source=hackmamba&utm_medium=hackmamba-blog)
- [Appwrite Real-Time technology](https://appwrite.io/docs/realtime?utm_source=hackmamba&utm_medium=hackmamba-blog)