MSDTmt - Trail Making Test Application

What is the Trail Making Test (TMT)?

The Trail Making Test (TMT) is a standardized cognitive assessment used to evaluate visual attention, task-switching ability, and executive function. The test consists of two parts:

  • TMT-A: Connecting numbers in sequence (1-2-3...)
  • TMT-B: Alternating between numbers and letters (1-A-2-B...)

The test measures the completion time, errors, and other metrics that help assess cognitive function.

This project is a digital implementation of the Trail Making Test (TMT), providing randomly generated cognitive assessments for clinical evaluation. The application dynamically generates test circles, records user performance, and provides comprehensive performance metrics analysis, transforming the traditional paper-and-pencil TMT into a reliable and consistent digital experience.

Project Structure

This project follows Clean Architecture with a Feature-First structure. Code is organized by feature, each as a self-contained module.

It uses GetX for state management, dependency injection, routing, and utilities.

Project Directory Structure

The project follows a typical Feature-First directory organization with Clean Architecture layers:

lib/
+---app/
|   +---config/                    # Application-wide configuration
|   |   +---routes/                # Route definitions
|   |   +---themes/                # Theme configurations
|   |   +---translation/           # Internationalization
|   +---constans/                  # Constants used across the app
|   +---features/                  # Feature modules (Feature-First)
|   |   +---home/                  # Home feature
|   |   |   +---data/              # Data layer
|   |   |   |   +---datasources/   # Data sources (local/remote)
|   |   |   |   +---repositories/  # Repository implementations
|   |   |   +---domain/            # Domain layer
|   |   |   |   +---entities/      # Business models
|   |   |   |   +---repository/    # Repository interfaces
|   |   |   |   +---usecases/      # Use cases (business logic)
|   |   |   +---presentation/      # Presentation layer
|   |   |       +---binding/       # Dependency injection
|   |   |       +---components/    # UI components
|   |   |       +---controllers/   # GetX controllers
|   |   |       +---screens/       # Screen widgets
|   |   +---splash/                # Splash screen feature
|   |   +---tm_tst/                # Trail Making Test feature
|   |   |   +---data/              
|   |   |   |   +---datasources/   
|   |   |   |   +---repositories/  
|   |   |   +---domain/            
|   |   |   |   +---entities/      
|   |   |   |   |   +---metric/    # Test metrics entities
|   |   |   |   |   +---result/    # Test result entities
|   |   |   |   |   +---tmt_game/  # Game-specific entities
|   |   |   |   +---repository/    
|   |   |   |   +---usecases/      
|   |   |   |       +---tmt_result/# Result-related use cases
|   |   |   +---presentation/      
|   |   |       +---bindings/      
|   |   |       +---components/    
|   |   |       +---controllers/   
|   |   |       +---screens/       
|   |   +---user/                  # User management feature
|   |       +---data/              
|   |       |   +---datasources/   
|   |       +---domain/            
|   |       |   +---entities/      
|   |       |   +---repository/    
|   |       |   +---usecase/       
|   |       +---presentation/      
|   |           +---binding/       
|   |           +---components/    
|   |           +---contoller/     
|   |           +---screen/        
|   +---shared_components/         # Shared UI components
|   +---utils/                     # Utilities
|       +---helpers/               # Helper functions
|       +---mixins/                # Shared behavior
|       +---services/              # Services
|       |   +---net/               # Network services
|       +---ui/                    # UI utilities

This structure demonstrates how the application organizes code:

  • Feature-First: Each feature (home, splash, tm_tst, user) has its own dedicated directory
  • Clean Architecture: Each feature follows the clean architecture layers (data, domain, presentation)
  • Shared Resources: Common components and utilities are separated from features
  • Consistency: The same structure is repeated across all features for maintainability

Clean Architecture Overview

Clean Code Architecture

The implementation organizes the application into five main components:

1. Config

Contains configuration-related classes:

  • Routing: Manages screen navigation and routes using GetX route management
  • Themes: Defines light, dark, and custom themes
  • Translation: Handles multilingual text resources with GetX internationalization

2. Constants

Maintains application-wide constants:

  • API Path: Centralized API endpoint definitions
  • Asset Path: Organized asset file references

3. Features

Core functionality organized by feature:

  • Model: Data models representing screen information
  • View: UI components and screen layouts
  • Controller: State management using GetX controllers

4. Shared Components

Reusable elements across features:

  • Widget: Custom UI elements (cards, buttons, etc.)
  • Style: Common styling configurations

5. Utils

Helper utilities:

  • Helper: Extension functions, type converters, etc.
  • Mixin: Reusable behavior for navigation, validation, etc.
  • Service: API clients, database connections, native functionality
  • UI: Common dialog boxes, snackbars, etc.

Feature Architecture

Each feature follows a layered architecture that enforces separation of concerns:

Feature Architecture

Data Layer

  • Remote Data Sources: Handles API interactions
  • Local Data Sources: Manages database and device storage
  • Models: Data transfer objects
  • Repositories (Implementation): Implements the interfaces defined in the domain layer

Domain Layer

  • Entities: Core business objects
  • Repositories (Interface): Defines data access contracts
  • Use Cases: Encapsulates business logic

Presentation Layer

  • Presentation Logic Holders: State management using GetX controllers
  • Widgets: UI components specific to the feature

Data Flow

  1. UI events trigger controller methods
  2. Controllers invoke use cases
  3. Use cases interact with repositories
  4. Repositories coordinate between data sources
  5. Results flow back up through the layers
  6. UI updates based on the new state and GetX reactive variables

This architecture ensures that:

  • Business logic remains independent of UI and external frameworks
  • Dependencies point inward (outer layers depend on inner layers)
  • Components are highly testable through dependency injection
  • The application is scalable and maintainable as features grow

References

Documentation

Viewing Project Documentation

The project's detailed documentation is located in the doc/build/html/index.html file. This documentation provides comprehensive information about the project's architecture, features, and implementation details.

To access the documentation:

  1. Navigate to the doc/build/html directory
  2. Open the index.html file in any web browser
  3. Browse through the complete documentation to understand all aspects of the project

The documentation includes detailed descriptions of:

  • Architecture and design patterns
  • Feature implementations
  • API interactions
  • User interfaces
  • Testing methodologies

For developers who want to understand or modify the documentation source, the RST files are available in the doc/source directory.

Running the Project

Prerequisites

Before running the project, users must create a .env file in the root directory with the following content:

API_BASE_URL=http://your_server_ip_address

Note: A backend server that supports the following API endpoints is required:

API Endpoints

  1. /procesar - Validate reference codes

    • Method: POST
    • Request Body:
      {
        "codeid": "reference_code_string"
      }
      
    • Response:
      {
        "exists": 2,
        "hands": [
          "D",
          "I"
        ],
        "message": "OK",
        "status": "ok"
      }
      
    • Description: Validates if a reference code is valid and returns whether it exists and which hand(s) were used previously
  2. /reportar - Submit TMT test results

    • Method: POST
    • Request Body: Combined user profile and test metrics data with the following format:
      codeid:123234-12
      F_nacimiento:MM-DD-YYYY
      Sexo:M
      Nivel_Educ:D
      Mano:D
      NumCirc:26
      Time_complete:156.6
      Number_Errors:2
      Average_Pause:2.5
      Average_Lift:0.7
      Average_Rate_Between_Circles:0.8
      Average_Rate_Inside_Circles:0.24
      Average_Time_Between_Circles:3.2
      Average_Time_Inside_Circles:2.1
      Average_Rate_Before_Letters:0.9
      Average_Rate_Before_Numbers:0.75
      Average_Time_Before_Letters:3.8
      Average_Time_Before_Numbers:1.98
      Number_Pauses:1
      Number_Lifts:2
      Average_Total_Pressure:12.5
      Average_Total_Size:3.0
      Date_Data:29-12-2025
      Score:36
      DiagInch:10.5
      
    • Response:
      {
        "status": "OK",
        "message": "Result saved successfully"
      }
      
    • Description: Submits detailed test performance metrics and user information
  3. /listar - Retrieve test results list

    • Method: POST
    • Request Body:
      {
        "codeid": "reference_code_string",
        "date_data": "YYYY-MM-DD"
      }
      
    • Response:
      {
        "status": "OK",
        "data": [
          {
            "date": "YYYY-MM-DD",
            "time_a": 45.3,
            "time_b": 75.2,
            "hand": "I/D",
             "": "// ...other result metrics"
          }
        ]
      }
      
    • Description: Returns a list of test results for a specific reference code and date

All responses include a status field that indicates success ("OK") or failure ("error"). In case of errors, a message field provides error details.

Running on Android

Debug Mode

flutter run --debug

Build for Release

flutter build apk --release

Running on iOS

Debug Mode

flutter run --debug

Build for Release

flutter build ipa

Build App Bundle for Play Store

Before building, add the following to android/local.properties:

storeFile=YOUR_PATH_TO_KEYSTORE
storePassword=YOUR_KEYSTORE_PASSWORD
keyAlias=YOUR_KEY_ALIAS
keyPassword=YOUR_KEY_PASSWORD

Then run:

flutter build appbundle --release

Output location:

  • Windows: .\build\app\outputs\bundle\release\
  • macOS/Linux: ./build/app/outputs/bundle/release/

Generating Documentation with Sphinx

Prerequisites

Ensure that Python is installed on your computer. You can verify this by running:

python --version

Windows

  1. Install Sphinx dependencies:
pip install -r doc/requirements.txt
  1. Navigate to the doc directory:
cd doc
  1. Generate the documentation:
make.bat html

Linux/macOS

  1. Install Sphinx:
pip install sphinx sphinx_rtd_theme
  1. Navigate to the doc directory:
cd doc
  1. Generate the documentation:
make html

Other Development Commands

Create Splash Screen

dart run flutter_native_splash:create

Generate Launcher Icons

flutter pub run flutter_launcher_icons

Libraries

app\config\routes\app_pages
app\config\routes\app_route_observer
app\config\themes\app_text_style_base
app\config\themes\app_theme
app\config\themes\AppColors
app\config\themes\AppFontWeight
app\config\themes\AppTextStyle
app\config\themes\input_decoration
app\config\themes\theme_controller
app\config\translation\app_translations
app\constans\app_constants
app\constans\database_constants
app\constans\send_tmt_result_date_formatter
app\constans\tmt_result_model_constant
app\features\home\data\repositories\reference_validation_repository_impl
app\features\home\domain\entities\home_ui_constant_variable
app\features\home\domain\entities\reference_validation_result_entity
app\features\home\domain\repository\reference_validation_repository
app\features\home\domain\usecases\validate_reference_code_use_case
app\features\home\presentation\binding\home_screen_binding
app\features\home\presentation\binding\reference_validation_biding
app\features\home\presentation\binding\select_user_profile_binding
app\features\home\presentation\components\home_card_button
app\features\home\presentation\components\home_page_header
app\features\home\presentation\components\reference_code_input
app\features\home\presentation\components\select_user_dropdown
app\features\home\presentation\components\select_user_profile_dialog
app\features\home\presentation\components\tmt_test_button_card
app\features\home\presentation\controllers\reference_code_controller
app\features\home\presentation\controllers\select_user_profile_controller
app\features\home\presentation\screens\home_page
app\features\splash\splash_screen
app\features\tm_tst\data\datasources\generate_circle_with_data
app\features\tm_tst\data\datasources\random_grid_sampler
app\features\tm_tst\data\datasources\reorder_circles
app\features\tm_tst\data\datasources\simple_generate_random_circle
app\features\tm_tst\data\model\pending_result_model
app\features\tm_tst\data\model\tmt_result_metric_model
app\features\tm_tst\data\model\tmt_reult_user_model
app\features\tm_tst\data\repositories\pending_result_repository_impl
app\features\tm_tst\data\repositories\tmt_game_config_repository_imp
app\features\tm_tst\data\repositories\tmt_result_repository_impl
app\features\tm_tst\domain\entities\metric\circles_metric
app\features\tm_tst\domain\entities\metric\metric_static_values
app\features\tm_tst\domain\entities\metric\tmt_b_metrics
app\features\tm_tst\domain\entities\metric\tmt_circles_metrics
app\features\tm_tst\domain\entities\metric\tmt_metrics_controller
app\features\tm_tst\domain\entities\metric\tmt_pressure_size_metric
app\features\tm_tst\domain\entities\metric\tmt_test_lift_metric
app\features\tm_tst\domain\entities\metric\tmt_test_pause_metric
app\features\tm_tst\domain\entities\metric\tmt_test_time_metric
app\features\tm_tst\domain\entities\result\tmt_game_hand_used
app\features\tm_tst\domain\entities\result\tmt_game_init_data
app\features\tm_tst\domain\entities\result\tmt_game_result_data
app\features\tm_tst\domain\entities\result\tmt_user_data
app\features\tm_tst\domain\entities\tmt_game\tmt_game_circle
app\features\tm_tst\domain\entities\tmt_game\tmt_game_variable
app\features\tm_tst\domain\repository\pending_result_repository
app\features\tm_tst\domain\repository\tmt_game_config_repository
app\features\tm_tst\domain\repository\tmt_result_repository
app\features\tm_tst\domain\usecases\select_mode_practice_or_test_responsive_calculate
app\features\tm_tst\domain\usecases\tmt_game_calculate
app\features\tm_tst\domain\usecases\tmt_game_config_use_case
app\features\tm_tst\domain\usecases\tmt_result\pending_result_use_case
app\features\tm_tst\domain\usecases\tmt_result\report_tmt_result_use_case
app\features\tm_tst\domain\usecases\tmt_result\tmt_result_card_responsive_calculate
app\features\tm_tst\domain\usecases\tmt_result\tmt_result_screen_responsive_calculator
app\features\tm_tst\presentation\bindings\tmt_game_config_biding
app\features\tm_tst\presentation\bindings\tmt_result_binding
app\features\tm_tst\presentation\bindings\tmt_test_binding
app\features\tm_tst\presentation\bindings\tmt_test_practice_binding
app\features\tm_tst\presentation\components\tmt_count_down_component
app\features\tm_tst\presentation\components\tmt_game_board_controller
app\features\tm_tst\presentation\components\tmt_painter
app\features\tm_tst\presentation\components\tmt_result_card
app\features\tm_tst\presentation\components\tmt_select_hand_dialog
app\features\tm_tst\presentation\components\tmt_test_app_bar
app\features\tm_tst\presentation\controllers\base_tmt_test_flow_contoller
app\features\tm_tst\presentation\controllers\tmt_practice_flow_state_contoller
app\features\tm_tst\presentation\controllers\tmt_result_report_controller
app\features\tm_tst\presentation\controllers\tmt_test_flow_state_controller
app\features\tm_tst\presentation\screens\tmt_select_mode_practice_or_test
app\features\tm_tst\presentation\screens\tmt_test_help
app\features\tm_tst\presentation\screens\tmt_test_practice_screen
app\features\tm_tst\presentation\screens\tmt_test_result_screen
app\features\tm_tst\presentation\screens\tmt_test_screen
app\features\user\data\datasources\test_result_data_soruce
app\features\user\data\datasources\user_profle_data_soruce
app\features\user\data\model\user_profile_model
app\features\user\data\model\user_test_result_local_data_model
app\features\user\domain\entities\user_profile
app\features\user\domain\entities\user_test_local_data_result
app\features\user\domain\repository\test_result_local_data_repository
app\features\user\domain\repository\user_profile_repository
app\features\user\domain\usecase\register_user_screen_responsive_calculator
app\features\user\presentation\binding\test_result_local_data_binding
app\features\user\presentation\binding\user_history_binding
app\features\user\presentation\binding\user_profile_binding
app\features\user\presentation\contoller\test_result_controller
app\features\user\presentation\contoller\user_profile_controller
app\features\user\presentation\screen\current_user_data_screen
app\features\user\presentation\screen\register_user_screen
app\features\user\presentation\screen\user_result_history_screen
app\features\user\presentation\screen\user_screen_base
app\shared_components\custom_app_bar
app\shared_components\custom_dialog
app\shared_components\custom_primary_button
app\shared_components\custom_secondary_button
app\shared_components\header_text
app\utils\helpers\app_helpers
app\utils\helpers\widget_max_width_calculator
app\utils\mixins\app_mixins
app\utils\services\app_logger
app\utils\services\local_storage_services
app\utils\services\native_api_services
app\utils\services\net\api_error
app\utils\services\net\api_interceptor
app\utils\services\net\rest_api_services
app\utils\services\net\result_data
app\utils\services\request_state
app\utils\services\user_data_base_helper
app\utils\services\user_data_base_migration
app\utils\services\work_manager_handler
app\utils\ui\ui_utils
main