Home

Awesome

AthleteX dApp UI

The world's leading Sports Digital Asset Exchange, focused on Sports, SportsFi, Athletes, and Athlete performance.

Learn more at our website: AthleteX.io

Getting Started πŸš€

<!-- Mnenomic --> <!-- web lady wheat index recipe chunk urge boost hungry critic language crossnote: this mnemonic is not secure; don't use it on a public blockchain. -->

Bloc Architecture ✨

Overview πŸ”

Layering our code is very important and helps us iterate quickly and with confidence. Each layer has a single responsibility and can be used and tested in isolation. This allows us to keep changes contained to a specific layer in order to minimize the impact on the entire application.

For example:

Layers πŸ“š

bloc_architecture_diagram

Data Layer

This layer is the lowest layer and is responsible for retrieving raw data from external sources(database, REST API, GraphQL backend) or device APIs. Usually packages in this layer will expose clients (e.g.: storage_client, location_client, auth0_api_client, etc...).

Note: This layer can be considered the "engineering" layer because it focuses on how to process/transform data in a performant way.

Domain Layer

This layer is a compositional layer meaning that it composes one or more data clients and applies "business rules" to the data. We call each component in this layer a repository (e.g.: user_repository, weather_repository, payments_repository, etc...).

Note: This layer can be considered the "product" layer. The business/product owner will determine the rules/acceptance criteria for how to combine data from one or more data providers into a unit that brings value to the customer.

Business Logic Layer

This layer composes one or more repositories and contains logic for how to surface the business rules via a specific feature or use-case. This layer uses the bloc package to manage the logic associated with each feature. We call each component in this layer a bloc (e.g.: login_bloc, weather_forecast_bloc, settings_bloc, etc...).

Note: This layer can be considered the "feature" layer. Design and product will determine the rules for how a particular feature will function.

Presentation Layer

This layer takes the state from the business logic layer and renders a UI for the customer to interact with. This layer uses the flutter_bloc package to render widgets based on the bloc's state and to allow the user to interact with the bloc through events.

Note: This layer can be considered the "design" layer. Designers will determine the user interface in order to provide the best possible experience for the customer.

Project Structure πŸ“

The project should adhere to the Multimodule Monorepo structure. This is an approach that compliments the layered architecture described above. It allows you to maintain a single repository(git) with multiple submodules. In some cases, data clients can be open-sourced and may eventually not be included in the project. Several benefits of maintaining a single project with multiple submodules are:

The application should use a feature-driven directory structure. This project structure enables us to scale the project by having self-contained features and allows developers to work on different features in parallel. Developers should make use of barrel files to export necessary files from any directory(except for bloc/cubit which are generated using vscode bloc extensions and make use of part and part of).

An example of a Multimodule Monorepo directory structure is below:

β”œβ”€β”€ lib
β”‚   β”œβ”€β”€ app
β”‚   β”‚   β”œβ”€β”€ bloc
β”‚   β”‚   β”œβ”€β”€ extensions
β”‚   β”‚   β”œβ”€β”€ models
β”‚   β”‚   └── view
β”‚   β”œβ”€β”€ home
β”‚   β”‚   └── view
β”‚   β”œβ”€β”€ l10n
β”‚   β”‚   └── arb
β”‚   β”œβ”€β”€ login
β”‚   β”‚   β”œβ”€β”€ bloc
β”‚   β”‚   β”œβ”€β”€ view
β”‚   β”‚   └── widgets
β”‚   β”œβ”€β”€ sign_up
β”‚   β”‚   β”œβ”€β”€ bloc
β”‚   β”‚   β”œβ”€β”€ view
β”‚   β”‚   └── widgets
β”œβ”€β”€ packages
β”‚   β”œβ”€β”€ meta_weather_api_client
β”‚   β”œβ”€β”€ user_repository
β”‚   └── weather_repository

Naming Conventions πŸ“

Formatting Conventions πŸ” 

Code formatters fix style, spacing, line jumps, comments, which helps enforce programming and formatting rules that can be easily automated. This helps reduce future code diffs by delegating formatting concerns to an automatic tool rather than individual developers.

flutter format --set-exit-if-changed lib test

Linting ⚠️

Code linters analyze code statically to flag programming errors, catch bugs, stylistic errors, and suspicious constructs.

flutter analyze lib test

Tests πŸ§ͺ

$ flutter test --coverage --test-randomize-ordering-seed random

Note: It's a good practice to aim at a code coverage as close to 100% as possible. Files/folders deemed to be unimportant can be excluded from the coverage so they don't affect it.

UI Best Practices βœ”οΈ

App UI πŸ“±

The project should contain an application package as a submodule having the role of an UI toolkit. This package is usually named app_ui or {appName}_ui and should contain the assets folder, reusable widgets, UI related helpers and classes for layout, navigation, platform, typography, theme, colors, etc...

An example of a class storing colors is below:

abstract class AppColors {
  static const Color black = Color(0xFF202124);

  static const Color white = Color(0xFFFFFFFF);
}

An example of the app_ui directory structure is below:

β”œβ”€β”€ lib
β”‚   β”œβ”€β”€ app
β”‚   └── l10n
β”œβ”€β”€ packages
β”‚   β”œβ”€β”€ app_ui
β”‚   β”‚   β”œβ”€β”€ assets
β”‚   β”‚   β”‚   β”œβ”€β”€ fonts
β”‚   β”‚   β”‚   └── images
β”‚   β”‚   β”œβ”€β”€ lib
β”‚   β”‚   β”‚   └── src
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ helpers
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ layout
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ navigation
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ platform
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ theme
β”‚   β”‚   β”‚   β”‚   └── widgets
β”‚   β”œβ”€β”€ meta_weather_api_client
β”‚   β”œβ”€β”€ user_repository
β”‚   └── weather_repository

very_good_cli can be used to easily create dart/flutter packages or even a full flutter application.

Note: Colors inside the app should be configured as much as possible through ColorScheme.

Translations 🌐

This project should rely on flutter_localizations and follow the official internationalization guide for Flutter. This approach is recommended even if there's only a locale needed.

Adding Strings

  1. To add a new localizable string, open the app_en.arb file at lib/l10n/arb/app_en.arb.
{
    "@@locale": "en",
    "counterAppBarTitle": "Counter",
    "@counterAppBarTitle": {
        "description": "Text shown in the AppBar of the Counter Page"
    }
}
  1. Then add a new key/value and description
{
    "@@locale": "en",
    "counterAppBarTitle": "Counter",
    "@counterAppBarTitle": {
        "description": "Text shown in the AppBar of the Counter Page"
    },
    "helloWorld": "Hello World",
    "@helloWorld": {
        "description": "Hello World Text"
    }
}
  1. Use the new string
import 'package:mindspotter/l10n/l10n.dart';

@override
Widget build(BuildContext context) {
  final l10n = context.l10n;
  return Text(l10n.helloWorld);
}

Adding Supported Locales

Update the CFBundleLocalizations array in the Info.plist at ios/Runner/Info.plist to include the new locale.

    ...

    <key>CFBundleLocalizations</key>
	<array>
		<string>en</string>
		<string>es</string>
	</array>

    ...

Adding Translations

  1. For each supported locale, add a new ARB file in lib/l10n/arb.
β”œβ”€β”€ l10n
β”‚   β”œβ”€β”€ arb
β”‚   β”‚   β”œβ”€β”€ app_en.arb
β”‚   β”‚   └── app_es.arb
  1. Add the translated strings to each .arb file:

app_en.arb

{
    "@@locale": "en",
    "counterAppBarTitle": "Counter",
    "@counterAppBarTitle": {
        "description": "Text shown in the AppBar of the Counter Page"
    }
}

app_es.arb

{
    "@@locale": "es",
    "counterAppBarTitle": "Contador",
    "@counterAppBarTitle": {
        "description": "Texto mostrado en la AppBar de la pΓ‘gina del contador"
    }
}