PWI Software Documentation Help

Flutter Development Standards

General Guidelines

Use Style and Colors from Theme

We almost always use colors and text styles from the theme. This maintains consistency throughout the app, reduces time spent coding, and allows us to easily change the look and feel of the app without having to change every widget.

Avoid setting font sizes directly in widgets. You can adjust font weight, color, and styles, but only when necessary to emphasize text or provide additional context. Change font sizes only in rare cases when explicitly necessary.

App themes are stored in the pwi_auth package. If the theme colors you want to use are not available, please add them to the pwi_auth package.

There are some cases where using semantic colors is necessary (ex. displaying specific data in a specific color). In these cases, it is good practice to define these colors in a separate file (e.g. semantic_colors.dart) for reuse throughout the app. In some cases it makes sense to define semantic colors inside of classes or enums themselves, when they are only used in one place.

Avoid Map Types

We try to avoid using the Map type in our Flutter applications. While maps can provide some great flexibility for dynamic key-value based storage, use of Map loses the benefit of type-safety and often makes code harder to read.

The only acceptable cases are:

  • When working directly with JSON type data (ex serializing, deserializing, api calls, etc.)

  • When temporarily organizing very large amounts of data within a method. In cases of large datasets, Map can provide a notable performance boost. Sharing Map objects between methods is discouraged.

Packages

Preferred Packages

We have a few packages that we prefer to use for our projects. Choosing different packages to accomplish the same goals should only be done with careful consideration and discussion among team members.

mvvm_plus

provides several classes and methods to greatly simplify implementing the MVVM architecture in Flutter.

bilocator

dependency injection library built for use with the mvvm_plus package.

fl_chart

a library for creating beautiful charts in Flutter. It is easy to use and has a lot of customization options.

go_router

a powerful routing library for Flutter. It is easy to use and has a lot of features, including deep linking, nested navigation, named routes, and more.

custom_adaptive_scaffold

a library that provides easy adaptive navigation in Flutter. Not to be confused with the outdated adaptive_scaffold and no longer maintained flutter_adaptive_scaffold packages.

Choosing New Packages

Flutter Gems is a great resource for finding new packages. It is a curated list of the best Flutter packages and plugins, and it is updated regularly.

There is also a lot of useful data in the Scores page of any pub.dev package.

When choosing a new package, consider the following:

  1. Popularity: Often packages gain popularity because they are well maintained and have a lot of community support. Check the number of likes, pub points, and downloads. Popularity is an especially useful factor when comparing two packages.

  2. Maintenance: Check the last update date and the number of open issues. If a library has not been updated in a long time or has a lot of open issues, it is likely not a good choice.

  3. Features: Make sure the package has the features you need. Check the documentation and examples to see if it meets your requirements.

Syncfusion Packages

Syncfusion has a large number of very well-developed packages and widgets. However, they are quite expensive to use and we unfortunately do not qualify for a community license.

App Architecture

We will use the MVVM (Model-View-ViewModel) architecture for all Flutter apps we develop. Use the MVVM+ package to assist in implementing this architecture. There's an article on Medium.com that explains the basics in more detail.

In general, our architecture is inspired by the Flutter documentation for App architecture. However, simple apps may not need to follow this architecture rigidly, with our actual code combining some of the concepts together (such as making a view model also function as its own repository). Ultimately, architecture will be discussed as a team as we begin development for a project.

Repository Structure

Typical MVVM applications structure views and view models into separate folders. However, this can lead to a lot of folders and files that are difficult to navigate. Instead of this structure, we will use the following:

lib ├ enums │ ├ pay_type.dart │ └ employment_status.dart ├ data │ ├ models │ │ ├ employee.dart │ │ └ project.dart │ ├ model_extensions │ │ ├ employee_extensions.dart │ │ └ project_extensions.dart │ ├ repositories │ │ ├ employee_repository.dart │ │ └ project_repository.dart │ └ services │ ├ employee_service.dart │ └ project_service.dart ├ domain │ ├ models │ │ ├ project_with_salesman.dart │ │ └ projects_by_salesman.dart │ └ use_cases │ └ combine_projects_and_salesmen.dart ├ system │ ├ app_router.dart │ ├ firebase_config.dart │ └ global_controller.dart ├ ui │ ├ <PAGE_NAME> │ │ ├ view.dart │ │ └ view_view_model.dart │ └ widgets │ ├ shared_widget_a.dart │ └ shared_widget_b.dart ├ utils │ ├ domain │ │ └ use_case_utils.dart │ ├ ui │ │ └ ui_utils.dart │ ├ date_utils.dart │ └ string_extensions.dart ├ app.dart ├ app_view_model.dart ├ constants.dart └ main.dart

Key points of this structure for UI that differs from the standard MVVM structure:

  1. Each page is given its own folder.

  2. ViewModels and widgets that are specific to a page are placed into their own UI folder.

  3. Shared widgets are kept in the ui/widgets folder.

When to Organize Files Into Subfolders

A good rule of thumb to follow when organizing files into subfolders is to create a folder only if:

  • the folder will contain three or more files

or

  • the file(s) in a folder are significantly different in nature or usage from other files in the project (e.g. a ui/home folder that only contains a view and view model, or a utils folder that only contains a single utility file).

22 September 2025