getBoolean / flutter_boolean_template

MIT License
11 stars 0 forks source link

flutter_boolean_template

latest release coverage Codemagic build status

An opinionated starting point for a Flutter app intended to provide the boilerplate needed to create a large app and provides utilities to separate code generation into separate packages.

Table of Contents

Motivation

This is an opinionated template I use for my personal projects. It uses melos monorepo to separate the code generation into separate packages for assets/, env/, and localization/

This repository also follows Riverpod App Architecture, I highly recommend reading the article. Each layer has its own folder per feature in the lib/src/features/ folder.

About

Demo

Flutter Web is deployed to GitHub Pages in a separate subfolder for each branch. The main branch is deployed to getboolean.github.io/flutter_boolean_template.

For example, in the CI workflow using the argument --dart-define ENABLE_HASH_URL_STRATEGY=true

void main() {
  const useHashUrlStrategy = bool.fromEnvironment('ENABLE_HASH_URL_STRATEGY', defaultValue: false);
  if (!useHashUrlStrategy) {
    setUrlStrategy();
  }
  runApp(MyApp());
}

Template: Getting Started

  1. Setup:
    1. [ ] Install puro Flutter Environment Manager
    2. [ ] Install Flutter using Puro
    3. [ ] Install Melos globally
    4. [ ] Install Mason CLI
  2. [ ] Run melos bootstrap to install dependencies for all packages and generate env files.
  3. [ ] Rename App: Change App/Package Name
  4. [ ] Workflow Permissions
  5. [ ] Update Description: pubspec.yaml and README.md.
  6. [ ] Replace codemagic.io badge with your own.
  7. [ ] Add Environment Variables: ENVied Environment Variables section for details.
  8. [ ] Change App Icon: flutter_launcher_icons
  9. [ ] Change Splash Screen: flutter_native_splash
  10. [ ] Setup the release build configuration, see the Building section.
  11. [ ] Setup Codecov for the repository, see the Codecov documentation.
  12. [ ] Update contribution guidelines at the Contributing section.
  13. [ ] (Important!) Update the LICENSE file. I give permission to relicense any code provided in this template, but the licenses of the packages must still be followed.
  14. [ ] Delete this Template: Getting Started section from the README.

Change App/Package Name

  1. [ ] Run the following command to change the package name, where com.author.app_name is the new name for the app.

    dart run change_app_package_name:main com.author.app_name
  2. [ ] Search for getBoolean/flutter_boolean_template and update it with your GitHub username and repository name

  3. [ ] Search for com.example.flutter_boolean_template and replace it with your new Android bundle identifier

  4. [ ] Search for com.example.flutterBooleanTemplate and replace it with your new iOS bundle identifier

  5. [ ] Search for flutter_boolean_template and replace it with your new package identifier

  6. [ ] Search for Flutter Boolean Template and replace it with your new app name

Workflow Permissions

  1. Github Repo: Settings -> Actions -> General -> Workflow permissions
    1. Enable "Read and write permissions"
    2. Enable "Allow GitHub Actions to create and approve pull requests"
  2. Github Repo: Settings -> Environments -> github-pages -> Deployment branches and tags
    1. Change "Selected branches and tags" to "No restriction"
  3. Github Repo: Settings -> Secrets and variables -> Repository secrets -> New repository secret
    1. Name: PAT
    2. Value: Your GitHub Personal Access Token
      1. Github Profile -> Settings -> Developer settings -> Personal access tokens -> Tokens (classic)
      2. Generate a new token (classic), name it <AppName> Web Deploy, and give it the repo and workflow scopes
  4. Github Repo: Settings -> General -> Pull Requests -> Enable "Allow auto-merge"

Setup

  1. Install puro Flutter Environment Manager
    • Install Flutter using Puro
  2. Install Melos globally
  3. Install Mason CLI
  4. Run melos bootstrap to install dependencies for all packages and generate env files.

Testing

melos run test

Integration Tests

patrol provides visual feedback to the tester andtakes screenshots automatically. These integration tests are located in the integration_test directory.

To run the tests, see the instructions in the Patrol documentation

Building

This project automatically builds for all platforms without code signing using GitHub Actions. To build the project locally, follow the instructions in the Flutter docs.

Flavors

Flavors are used to provide different environment variables based on the current flavor. By default, the app uses the "local" flavor. Run/build the app with --dart-define FLAVOR=<flavorname> to change the flavor. The following flavors are supported:

Build for Windows Release

  1. Customize msix_config in pubspec.yaml according to the documentation for msix for your method of publication. The default configuration is for CI/CD testing builds only, not releases.
  2. Run the corresponding command for your method of publication

Build for other platforms

Architecture

This project uses the Riverpod App Architecture in a feature-first manner where each feature is a separate package in the lib/src/features/ folder. Each feature has its own layers, which separate the business logic from the UI.

Data Layer (Repositories)

The repository pattern consists of Repositories, DTOs, and Data Sources. Their jobs are the following:

  1. isolate domain models (or entities) from the implementation details of the data sources in the data layer.
  2. convert data transfer objects to validated entities that are understood by the domain layer
  3. (optionally) perform operations such as data caching.

Repository pattern use cases:

  1. talking to REST APIs
  2. talking to local or remote databases (e.g. Sembast, Hive, Firestore, etc.)
  3. talking to device-specific APIs (e.g. permissions, camera, location, etc.)

Domain Layer (Models)

Domain Models, which consist of entity and value objects. It should solve domain-related problems.

The domain models can contain logic for mutating them in an immutable manner, but they should not contain any serialization.

Presentation Layer (Controllers)

Application Layer (Service)

Implements application-specific logic by accessing the relevant repositories as needed. The service classes are not concerned about:

Libraries

Melos

This project uses Melos to manage the monorepo.

  flutter pub get
  # Install melos globally
  dart pub global activate melos
  # Setup local dependency overrides for packages in the monorepo
  melos bootstrap

  # Or if dart executables are not on your path
  dart pub global run melos bootstrap

Scripts

Pub:

Code Generation:

Tests:

GoRouter Navigation

This project uses GoRouter for navigation and provides some starter boilerplate for adaptive multitab navigation using ResponsiveScaffold.

ENVied Environment Variables

Environment variables are setup using ENVied in the env package. Environment variables need to be defined for debug, profile, and release modes.

  1. Copy the *.env.example files and remove the .example extension from them.
  2. Add the values for the environment variables in the respective .env* file.
    • Each key must be added to each .env* file, unless a non null default value is added to the @EnviedField annotation.
    • It is recommended to use an empty string for the default and use Env's getter to access the value.
  3. Update src/env/app_env_fields.dart with the new environment variables for AppEnvFieldsGenerated and AppEnvFieldsNullable.
  4. Add the new environment variables to the implementing *Env classes in the src/env directory.
    • It must be done for all even if only one .env file is planned to be used
  5. Enable obfuscate for API keys in the @EnviedField annotation. (Note: still assume it is not secure)
  6. Optionally, add a @EnviedField defaultValue or enable optional on the annotation for keys which are not required in all modes.

Mason Bricks

Mason to generate code for features and tests using templates. To use the bricks, install the Mason VS Code extension. To create addition bricks, use Mason CLI.

JSON Serialization, Unions, Sealed Classes and copyWith

State Management

This project is preconfigured to use Riverpod Generator. The normal riverpod syntax is still supported. See Andrea's article on Riverpod architecture for how to structure your code.

It is recommend to run build_runner in watch mode to generate the code for Riverpod.

dart run build_runner watch -d

Async Data Loading and Caching

The stock package is recommended for loading data from both remote and local sources. Its main goal is to prevent excessive calls to the network and disk cache. By utilizing it, you eliminate the possibility of flooding your network with the same request while, at the same time, adding layers of caching.

Although you can use it without a local source, the greatest benefit comes from combining Stock with a local database such as Floor, Drift, Sqflite, Realm, etc. (excerpt from the README)

Native Splash Screen

Follow the instructions in the file flutter_native_splash.yaml

Native Platform Dialogs/Alerts

Use flutter_native_dialog to show native dialogs/alerts.

Bottom Sheets

Use wolt_modal_sheet to show customizable and responsive bottom sheets.

Layout List/Grid

Use wolt_responsive_layout_grid to show a responsive list/grid.

Contributing

  1. Fork it https://github.com/getBoolean/flutter_boolean_template/fork
  2. Create your feature branch (git checkout -b feature/fooBar)
  3. Commit your changes (git commit -am 'Add some fooBar')
  4. Push to the branch (git push origin feature/fooBar)
  5. Create a new Pull Request