Use Appwrite and Flutter to build a serverless mobile wallet service
Tags: appwrite, flutter, mobilewallet, mobiledevelopment
Published: 2023-02-22 10:59:02

---
title: Use Appwrite and Flutter to build a serverless mobile wallet service
published: true
description: Learn how to use Appwrite’s database features to build a mobile wallet functionality in a Flutter application
tags: #Appwrite #flutter #mobileWallet #mobileDevelopment
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f3d7auja4g30hqnrkx64.png
# Use a ratio of 100:42 for best results.
# published_at: 2023-02-22 10:11 +0000
---

Mobile wallets are virtual/digital wallets that store information from loyalty cards, coupons, credit cards, and debit cards on smartphones or tablets. They offer a convenient way for users to make online and in-store payments.

In this post, we will learn how to use Appwrite’s database features to build a mobile wallet functionality in a Flutter application. The project’s GitHub repository can be found [here](https://github.com/Mr-Malomz/mobile_wallet/tree/dev).

## Prerequisites

To fully grasp the concepts presented in this tutorial, the following are required:

- Basic understanding of Dart and Flutter
- Flutter [SDK](https://flutter.dev/docs/get-started/install) installed
- [Xcode](https://developer.apple.com/xcode/) with a developer account (for Mac users)
- Either [i](https://developer.apple.com/xcode/)[OS Simulator](https://developer.apple.com/xcode/), [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 our application
- An Appwrite instance; check out this [article](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba) on how to set up an instance locally or install with one click on [DigitalOcean](https://marketplace.digitalocean.com/apps/appwrite) or [Gitpod](https://gitpod.io/#https://github.com/appwrite/integration-for-gitpod)


## Getting started

To get started, we need to clone the project by navigating to the desired directory and running the command below:

```bash
git clone https://github.com/Mr-Malomz/mobile_wallet.git
```

## Running the project

First, we need to install the project dependencies by running the command below:

```bash
flutter pub get
```

Then, run the project using the command below:

```bash
flutter run
```

The command above will run the application on the selected device.

![Home screen](https://paper-attachments.dropboxusercontent.com/s_84688A49881ED7B894BB54FC885948D95F94AEE77178A12FAD5ABA3FBC753CC7_1674391037432_Screenshot+2023-01-18+at+22.40.30.png)
![List of transactions](https://paper-attachments.dropboxusercontent.com/s_84688A49881ED7B894BB54FC885948D95F94AEE77178A12FAD5ABA3FBC753CC7_1674391037451_Screenshot+2023-01-18+at+23.09.49.png)



## Set up mobile wallet service on Appwrite

To get started, we need to log into our Appwrite console, click the **Create project** button, input `mobile_wallet` as the name, and then click **Create**.

![Create project](https://paper-attachments.dropboxusercontent.com/s_342E9FE96DE03D24E8AD672738F224A92FC913F6592531FAD506815CB3E2A539_1672866342209_Screenshot+2023-01-04+at+22.05.19.png)


**Create a database, collection, attributes, and add sample data**
With our project created, we can set up our application database. First, navigate to the **Database** tab, click the **Create database** button, input `wallet` as the name, and then click **Create**.

![Create database](https://paper-attachments.dropboxusercontent.com/s_84688A49881ED7B894BB54FC885948D95F94AEE77178A12FAD5ABA3FBC753CC7_1674391810309_Screenshot+2023-01-22+at+13.49.05.png)


Secondly, we need to create two collections for storing **user** details and the **transactions** performed on the wallet. To do this, click the **Create collection** button, input `users` as the name, and then click **Create**. Following the same approach, we must create a `transactions` collection.

![Users and transactions collection](https://paper-attachments.dropboxusercontent.com/s_84688A49881ED7B894BB54FC885948D95F94AEE77178A12FAD5ABA3FBC753CC7_1674392078725_Screenshot+2023-01-22+at+13.54.22.png)


Thirdly, we need to create attributes to represent our database fields. To do this, we need to navigate to the **Attributes** tab and create attributes for each of the collections, as shown below:

For the `users` collection:

| Attribute key | Attribute type | Size | Required |
| ------------- | -------------- | ---- | -------- |
| name          | string         | 250  | YES      |
| balance       | integer        | 5000 | YES      |



![Create attributes](https://paper-attachments.dropboxusercontent.com/s_84688A49881ED7B894BB54FC885948D95F94AEE77178A12FAD5ABA3FBC753CC7_1674392523265_Screenshot+2023-01-21+at+19.08.06.png)
![Users collection attributes](https://paper-attachments.dropboxusercontent.com/s_84688A49881ED7B894BB54FC885948D95F94AEE77178A12FAD5ABA3FBC753CC7_1674392580354_Screenshot+2023-01-22+at+14.02.51.png)


We also need to update our collection permission to manage them accordingly. To do this, we need to navigate to the **Settings** tab, scroll to the **Update Permissions** section, select `Any`, mark accordingly, and then click **Update**.

![Select any](https://paper-attachments.dropboxusercontent.com/s_1F2738109066A0A5582E754A3908A7FD06BE17296D17A867AFE208C1CA00E9C0_1671384434901_Screenshot+2022-12-18+at+02.24.27.png)
![Mark permission](https://paper-attachments.dropboxusercontent.com/s_84688A49881ED7B894BB54FC885948D95F94AEE77178A12FAD5ABA3FBC753CC7_1674393222298_Screenshot+2023-01-21+at+20.06.55.png)


For the `transactions` collection:

| Attribute key | Attribute type | Size | Required |
| ------------- | -------------- | ---- | -------- |
| userId        | string         | 250  | YES      |
| name          | string         | 250  | YES      |
| paymentMethod | string         | 250  | YES      |
| amount        | integer        | 5000 | YES      |



![Create attributes](https://paper-attachments.dropboxusercontent.com/s_84688A49881ED7B894BB54FC885948D95F94AEE77178A12FAD5ABA3FBC753CC7_1674393607752_Screenshot+2023-01-22+at+14.18.20.png)
![Transactions collection attributes](https://paper-attachments.dropboxusercontent.com/s_84688A49881ED7B894BB54FC885948D95F94AEE77178A12FAD5ABA3FBC753CC7_1674393481645_Screenshot+2023-01-21+at+20.03.42.png)


Following the same steps above, we also need to update the collection permission and update.


![Mark permission](https://paper-attachments.dropboxusercontent.com/s_84688A49881ED7B894BB54FC885948D95F94AEE77178A12FAD5ABA3FBC753CC7_1674393222298_Screenshot+2023-01-21+at+20.06.55.png)


Lastly, we need to add sample data to simulate our wallet data. To do this, we need to navigate to the **Document** tab, click the **Create document** button and add data for each of the collections as shown below:

For `users` document:

| name          | balance |
| ------------- | ------- |
| John Travolta | 1200    |

![Create data](https://paper-attachments.dropboxusercontent.com/s_84688A49881ED7B894BB54FC885948D95F94AEE77178A12FAD5ABA3FBC753CC7_1674395192479_Screenshot+2023-01-21+at+19.09.12.png)
![Created data](https://paper-attachments.dropboxusercontent.com/s_84688A49881ED7B894BB54FC885948D95F94AEE77178A12FAD5ABA3FBC753CC7_1674395528306_Screenshot+2023-01-21+at+19.09.24.png)


On creating the document, we also need to copy the document ID, as it will serve as a reference to the user when creating transactions.

![Copy document ID](https://paper-attachments.dropboxusercontent.com/s_84688A49881ED7B894BB54FC885948D95F94AEE77178A12FAD5ABA3FBC753CC7_1674395594798_Screenshot+2023-01-21+at+19.20.35.png)


For the `transactions` document:

| userId           | name              | paymentMethod    | amount |
| ---------------- | ----------------- | ---------------- | ------ |
| COPIED USER ID | Groceries         | internet payment | 10     |
| COPIED USER ID | Call subscription | NFT              | 15     |

![Create data](https://paper-attachments.dropboxusercontent.com/s_84688A49881ED7B894BB54FC885948D95F94AEE77178A12FAD5ABA3FBC753CC7_1674395718349_Screenshot+2023-01-21+at+20.04.13.png)
![Created data](https://paper-attachments.dropboxusercontent.com/s_84688A49881ED7B894BB54FC885948D95F94AEE77178A12FAD5ABA3FBC753CC7_1674395697103_Screenshot+2023-01-21+at+20.05.22.png)


**Add an index to the Transactions collection**
Databases use indexes to improve the speed of data retrieval. To add an index to the `transactions` collection, navigate to the **Indexes** tab, click **Create index** button, input `userId` as the index key, select `userId` as the attribute and `DESC` as the order, and then click **Create**.

![](https://paper-attachments.dropboxusercontent.com/s_84688A49881ED7B894BB54FC885948D95F94AEE77178A12FAD5ABA3FBC753CC7_1674398121451_Screenshot+2023-01-21+at+23.41.12.png)


**Add platform support**
To add support for our Flutter app, navigate to the **Home** menu and click the **Flutter App** button.

![Add platform](https://paper-attachments.dropboxusercontent.com/s_1F2738109066A0A5582E754A3908A7FD06BE17296D17A867AFE208C1CA00E9C0_1671388788364_Screenshot+2022-12-18+at+01.25.06.png)


Depending on the device being used to run the Flutter application, we can modify it as shown below.

**iOS**
To obtain our Bundle ID, we can navigate using the path below:
**ios > Runner.xcodeproj > project.pbxproj**

Open the `project.pbxproj` file and search for `PRODUCT_BUNDLE_IDENTIFIER`.

![Select new Flutter app](https://paper-attachments.dropboxusercontent.com/s_1F2738109066A0A5582E754A3908A7FD06BE17296D17A867AFE208C1CA00E9C0_1671388862700_Screenshot+2022-12-18+at+01.30.54.png)


Next, open the project directory on [Xcode](https://developer.apple.com/xcode/), open the `Runner.xcworkspace` folder in the app's iOS folder, select the **Runner** project in the Xcode project navigator, select the **Runner** target in the primary menu sidebar, and then select **i****OS 11** in the deployment info’s target.

![Change deployment target](https://paper-attachments.dropboxusercontent.com/s_9C6F95223612512F2BFCBBAA719BAF62E5E51518F8EC1B3A16905A2D91336244_1650208061820_Screenshot+2022-04-17+at+16.05.22.png)


**Android**
To get our package name, we can navigate to an XML file using the following path:
**android > app > src > debug > AndroidManifest.xml**

Open the `AndroidManifest.xml` file and copy the `package` value.

![Android](https://paper-attachments.dropboxusercontent.com/s_1F2738109066A0A5582E754A3908A7FD06BE17296D17A867AFE208C1CA00E9C0_1671389594719_Screenshot+2022-12-18+at+01.25.50.png)


Next, we need to modify the `AndroidManifext.xml` as shown below:

```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.mobile_wallet">
    <uses-permission android:name="android.permission.INTERNET"/>
    <application ...>
    <activity android:name="com.linusu.mobile_wallet.CallbackActivity" android:exported="true">
      <intent-filter android:label="mobile_wallet">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="appwrite-callback-[PROJECT_ID]" />
      </intent-filter>
    </activity>
  </application>
</manifest>
```

We must also replace the highlighted `[PROJECT_ID]` with our actual Appwrite project ID.


## Building the mobile wallet service

With all that done, let’s build the mobile wallet service. First, we need to create models to convert the response sent from Appwrite to a Dart object. The models will also cater to JSON serialization. To do this, we need to create a `utils.dart` file in the `lib` folder and add the snippet below:

```dart
class AppConstant {
  final String databaseId = "REPLACE WITH DATABASE ID";
  final String projectId = "REPLACE WITH PROJECT ID";
  final String userCollectionId = "REPLACE WITH USERS COLLECTION ID";
  final String transactionCollectionId = "REPLACE WITH TRANSACTIONS COLLECTION ID";
  final String userId = "REPLACE WITH SAMPLE ID";
  final String endpoint = "ENDPOINT";
}

class User {
  String? $id;
  String name;
  int balance;

  User({this.$id, required this.name, required this.balance});

  Map<dynamic, dynamic> toJson() {
    return {"name": name, "balance": balance};
  }

  factory User.fromJson(Map<dynamic, dynamic> json) {
    return User(
        $id: json['\$id'], name: json['name'], balance: json['balance']);
  }
}

class Transaction {
  String? $id;
  String userId;
  String name;
  String paymentMethod;
  int amount;

  Transaction({
    this.$id,
    required this.userId,
    required this.name,
    required this.paymentMethod,
    required this.amount,
  });

  Map<dynamic, dynamic> toJson() {
    return {
      "userId": userId,
      "name": name,
      "paymentMethod": paymentMethod,
      "amount": amount
    };
  }

  factory Transaction.fromJson(Map<dynamic, dynamic> json) {
    return Transaction(
        userId: json['userId'],
        name: json['name'],
        paymentMethod: json['paymentMethod'],
        amount: json['amount']);
  }
}
```

We’ll need to modify the `endpoint` property so that it can work with our system's local network address. We can adjust accordingly:

**iOS**
Navigate to the **Network** section and copy the IP address.

![IP address](https://res.cloudinary.com/dtgbzmpca/image/upload/v1677062661/ios_ip.png)


**Android**
We can connect our Android emulator to the system’s IP using the `10.0.2.2` IP address.

```dart
final String endpoint = "http://10.0.2.2/v1";
```

**Note**: We can get the `databaseId`, `projectId`, `collectionId`s, `functionId`, and `userId` by navigating through the Appwrite console.

Next, we must create a service file to separate the application core logic from the UI. To do this, create a `wallet_service.dart` file inside the `lib` directory. Then add the snippet below:

```dart
import 'package:appwrite/appwrite.dart';
import 'package:mobile_wallet/utils.dart';

class WalletService {
  Client _client = Client();
  Databases? _db;

  WalletService() {
    _init();
  }

  //initialize the application
  _init() async {
    _client
        .setEndpoint(AppConstant().endpoint)
        .setProject(AppConstant().projectId);
    _db = Databases(_client);

    //get current session
    Account account = Account(_client);
    try {
      await account.get();
    } on AppwriteException catch (e) {
      if (e.code == 401) {
        account
            .createAnonymousSession()
            .then((value) => value)
            .catchError((e) => e);
      }
    }
  }
}
```

The snippet above does the following:

- Imports the required dependencies
- Creates a `WalletService` class with `_client`, `_db` properties to connect to the Appwrite instance and the database
- Creates an `_init` method that configures Appwrite using the properties and also conditionally creates an anonymous user to access the Appwrite database

Lastly, we need to modify the `WalletService` class by adding `getUserDetails`, `updateUserBalance`, `createTransaction`, and `getTransactions` methods that use the `_db` property to manage wallet operations accordingly.

```dart
//imports go here

class WalletService {
  Client _client = Client();
  Databases? _db;

  WalletService() {
    _init();
  }

  //initialize the application
  _init() async {
    //init code goes here
  }

  Future<User> getUserDetails() async {
    try {
      var data = await _db?.getDocument(
          databaseId: AppConstant().databaseId,
          collectionId: AppConstant().userCollectionId,
          documentId: AppConstant().userId);
      var user = data?.convertTo((doc) => User.fromJson(doc));
      return user!;
    } catch (e) {
      throw Exception('Error getting user details');
    }
  }

  Future updateUserBalance(
    String userId,
    String name,
    int balance,
    int amount,
  ) async {
    int newBalance = balance - amount;
    try {
      User updatedUserBalance = User(name: name, balance: newBalance);
      var result = await _db?.updateDocument(
          databaseId: AppConstant().databaseId,
          collectionId: AppConstant().userCollectionId,
          documentId: userId,
          data: updatedUserBalance.toJson());
      return result;
    } catch (e) {
      throw Exception('Error updating user balance!');
    }
  }

  Future createTransaction(String userId, int amount) async {
    try {
      Transaction updatedTransaction = Transaction(
        userId: userId,
        name: "Stamp duty",
        paymentMethod: "internet payment",
        amount: amount,
      );
      var data = await _db?.createDocument(
        databaseId: AppConstant().databaseId,
        collectionId: AppConstant().transactionCollectionId,
        documentId: ID.unique(),
        data: updatedTransaction.toJson(),
      );
      return data;
    } catch (e) {
      throw Exception('Error creating transaction!');
    }
  }

  Future<List<Transaction>> getTransactions() async {
    try {
      var data = await _db?.listDocuments(
        databaseId: AppConstant().databaseId,
        collectionId: AppConstant().transactionCollectionId,
        queries: [Query.orderDesc('userId')],
      );
      var transactionList = data?.documents
          .map((transaction) => Transaction.fromJson(transaction.data))
          .toList();
      return transactionList!;
    } catch (e) {
      throw Exception('Error getting list of transactions!');
    }
  }
}
```

**P.S.**: *In the* `createTransaction` *method**,* *we hard-coded transaction details for simulation purposes.*


## Consuming the service

With that done, we can start using the service to perform the required operation.

**Get users’ details and create a transaction**
To get started, we need to modify the `home.dart` file in the  `screens` directory and update it by doing the following:

First, we need to import the required dependencies and create methods to get user details and create a transaction:

```dart
import 'package:flutter/material.dart';
import 'package:mobile_wallet/screens/transactions.dart';
import 'package:mobile_wallet/utils.dart';
import 'package:mobile_wallet/wallet_service.dart';

class Home extends StatefulWidget {
  const Home({super.key});
  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  late User user;
  bool _isLoading = false;
  bool _isTransacting = false;
  bool _isError = false;

  @override
  void initState() {
    _getUserDetails();
    super.initState();
  }

  _getUserDetails() {
    setState(() {
      _isLoading = true;
    });
    WalletService().getUserDetails().then((value) {
      setState(() {
        user = value;
        _isLoading = false;
      });
    }).catchError((e) {
      setState(() {
        _isLoading = false;
        _isError = true;
      });
    });
  }

  _createTransaction(String userId, String name, int balance) {
    setState(() {
      _isTransacting = true;
    });
    int amount = 20;
    WalletService().createTransaction(userId, amount).then((value) {
      WalletService()
          .updateUserBalance(userId, name, balance, amount)
          .then((value) {
        //update balance in app
        int newBalance = user.balance - amount;
        setState(() {
          _isTransacting = false;
          user.balance = newBalance;
        });
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('Transaction created successfully!')),
        );
      }).catchError((e) {
        setState(() {
          _isTransacting = false;
        });
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('Error creating transaction!')),
        );
      });
    }).catchError((e) {
      setState(() {
        _isTransacting = false;
      });
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Error creating transaction!')),
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    //UI code goes here
  }
}
```

The snippet above does the following:

- **Lines 1-4**: Import the required dependencies
- **Line 13-16**: Create the `user`, `_isLoading`, `_isTransacting`, and `_isError` properties to manage application state
- **Lines 18-39**: Create a `_getUserDetails` method to get the user details using the `WalletService().getUserDetails` service, set states accordingly, and use the `initState` method to call the `_getUserDetails`
- **Lines 41-75**: Create a `_createTransaction` method to simulate a transaction using the `WalletService().createTransaction` service, and on successful creation, uses the  `WalletService().updateUserBalance` service to update the wallet balance

Lastly, we need to modify the UI to conditionally show the users' details and simulate a transaction using the methods and states created above.

```dart
//import goes here

class Home extends StatefulWidget {
  //code goes here
}

class _HomeState extends State<Home> {
  //states goes here

  @override
  void initState() {
    _getUserDetails();
    super.initState();
  }

  _getUserDetails() {
    //code goes here
  }

  _createTransaction(String userId, String name, int balance) {
    //code goes here
  }

  @override
  Widget build(BuildContext context) {
    return _isLoading
        ? const Center(
            child: CircularProgressIndicator(
            color: Colors.blue,
          ))
        : _isError
            ? const Center(
                child: Text(
                  'Error getting users details',
                  style: TextStyle(
                    color: Colors.red,
                    fontWeight: FontWeight.bold,
                  ),
                ),
              )
            : Scaffold(
                backgroundColor: Colors.white,
                body: Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      Image.asset('images/wallet.jpg'),
                      const SizedBox(height: 40.0),
                      const Text(
                        'WALLET BALANCE',
                        style: TextStyle(
                            fontSize: 12.0, fontWeight: FontWeight.w500),
                      ),
                      const SizedBox(height: 5.0),
                      Text(
                        '\$ ${user.balance}',
                        style: TextStyle(
                            fontSize: 32.0, fontWeight: FontWeight.bold),
                      ),
                      const SizedBox(height: 40.0),
                      Padding(
                        padding: const EdgeInsets.symmetric(horizontal: 10.0),
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            OutlinedButton(
                              onPressed: () {
                                Navigator.push(
                                  context,
                                  MaterialPageRoute(
                                      builder: (context) =>
                                          const Transactions()),
                                );
                              },
                              child: Text(
                                'View transactions',
                                style: TextStyle(
                                    fontSize: 12.0,
                                    fontWeight: FontWeight.bold,
                                    color: Colors.black),
                              ),
                              style: ButtonStyle(
                                shape: MaterialStateProperty.all(
                                  RoundedRectangleBorder(
                                    borderRadius: BorderRadius.circular(5.0),
                                  ),
                                ),
                                side: MaterialStateProperty.all(
                                  const BorderSide(
                                      color: Colors.black,
                                      width: 1.5,
                                      style: BorderStyle.solid),
                                ),
                              ),
                            ),
                            const SizedBox(width: 20.0),
                            TextButton(
                              onPressed: _isTransacting
                                  ? null
                                  : () {
                                      _createTransaction(
                                        user.$id.toString(),
                                        user.name,
                                        user.balance,
                                      );
                                    },
                              child: Text(
                                'Spend from wallet',
                                style: TextStyle(
                                    fontSize: 12.0,
                                    fontWeight: FontWeight.bold,
                                    color: Colors.white),
                              ),
                              style: ButtonStyle(
                                  backgroundColor:
                                      MaterialStateProperty.all(Colors.black),
                                  side: MaterialStateProperty.all(
                                    const BorderSide(
                                        color: Colors.black,
                                        width: 1.5,
                                        style: BorderStyle.solid),
                                  ),
                                  padding:
                                      MaterialStateProperty.all<EdgeInsets>(
                                    const EdgeInsets.symmetric(
                                        horizontal: 15.0),
                                  )),
                            ),
                          ],
                        ),
                      )
                    ],
                  ),
                ),
              );
  }
}
```

**Get the list of transactions**
To obtain the list of transactions, we need to modify the `transactions.dart` file in the same `screens` directory as shown below:

```dart
import 'package:flutter/material.dart';
import 'package:mobile_wallet/utils.dart';
import 'package:mobile_wallet/wallet_service.dart';

class Transactions extends StatefulWidget {
  const Transactions({super.key});
  @override
  State<Transactions> createState() => _TransactionsState();
}
class _TransactionsState extends State<Transactions> {
  late List<Transaction> transaction;
  bool _isLoading = false;
  bool _isError = false;

  @override
  void initState() {
    _getTransactions();
    super.initState();
  }

  _getTransactions() {
    setState(() {
      _isLoading = true;
    });
    WalletService().getTransactions().then((value) {
      setState(() {
        transaction = value;
        _isLoading = false;
      });
    }).catchError((e) {
      setState(() {
        _isLoading = false;
        _isError = true;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return _isLoading
        ? const Center(
            child: CircularProgressIndicator(
            color: Colors.blue,
          ))
        : _isError
            ? const Center(
                child: Text(
                  'Error getting list of transactions',
                  style: TextStyle(
                    color: Colors.red,
                    fontWeight: FontWeight.bold,
                  ),
                ),
              )
            : Scaffold(
                appBar: AppBar(
                  title: const Text('Transactions'),
                  backgroundColor: Colors.black,
                ),
                body: ListView.builder(
                  itemCount: transaction.length,
                  itemBuilder: (context, index) {
                    return Container(
                      decoration: const BoxDecoration(
                        border: Border(
                          bottom: BorderSide(width: .5, color: Colors.grey),
                        ),
                      ),
                      padding: EdgeInsets.fromLTRB(10, 20, 10, 20),
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                        children: [
                          Expanded(
                            flex: 7,
                            child: Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: [
                                Text(
                                  transaction[index].name,
                                  style: TextStyle(
                                      color: Colors.black,
                                      fontWeight: FontWeight.w800),
                                ),
                                SizedBox(height: 10.0),
                                Text(transaction[index].paymentMethod)
                              ],
                            ),
                          ),
                          Column(
                            crossAxisAlignment: CrossAxisAlignment.end,
                            children: [
                              SizedBox(height: 10.0),
                              Text('\$ ${transaction[index].amount}')
                            ],
                          ),
                        ],
                      ),
                    );
                  },
                ),
              );
  }
}
```

The snippet above does the following:

- **Lines 1-3**: Import the required dependencies
- **Lines 11-13**: Create the `transactions`, `_isLoading`, and `_isError` properties to manage the application state
- **Lines 15-36**: Create a `_getTransactions` method to get the list of transactions using the `WalletService().getTransactions` service, set states accordingly, and use the `initState`  method to call the `_getTransactions` method when the object is inserted into the tree
- Modifies the UI widgets to show the transactions stored on Appwrite

With that done, we restart the application using the code editor or run the command below:

```bash
flutter run
```


![](https://media.giphy.com/media/f7i8RWsiXAIdXDOoBW/giphy.gif)


[https://media.giphy.com/media/f7i8RWsiXAIdXDOoBW/giphy.gif](https://media.giphy.com/media/f7i8RWsiXAIdXDOoBW/giphy.gif)
 

## Conclusion

This post discussed how to use Appwrite’s database features to build a mobile wallet functionality in a Flutter application. We built a base implementation to demonstrate Appwrite's support for scaffolding a working prototype. With Appwrite, we can further extend the application's functionality by leveraging features like real-time communication, localization, authentication, etc

These resources may 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 Database Indexes](https://appwrite.io/docs/databases#indexes?utm_source=hackmamba&utm_medium=hackmamba-blog)