Architecture
CNVRT follows clean architecture principles with clear separation of concerns across three main layers.
Layered Architecture
┌─────────────────────────────────────────────┐
│ UI Layer │
│ (Screens, Widgets, Theme) │
└──────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ State Management │
│ (Riverpod Providers & Notifiers) │
└──────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Domain Layer │
│ (Business Logic, Models, Constants) │
└──────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ IO Layer │
│ (Settings, Repositories, Data Sources) │
└──────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Data Sources │
│ (Dio HTTP Client, Drift Database) │
└─────────────────────────────────────────────┘
Layer Responsibilities
UI Layer (lib/ui/)
- Screens and widgets organized by feature
- Consumes Riverpod providers for reactive updates
- Theme configuration and styling
- User interaction handling
State Management (lib/domain/di/providers/)
- Riverpod providers with annotation-based code generation
- State notifiers for complex state logic
- Selector providers for derived state
- Feature-based organization (currencies, settings, units)
Domain Layer (lib/domain/)
- Business models and entities
- Application constants and configuration
- Extension methods and utilities
- Feature interfaces
IO Layer (lib/io/, lib/db/)
- Repository pattern implementation
- Settings persistence via SharedPreferences
- Database tables and queries via Drift
- API client configuration
Project Structure
cnvrt/
├── lib/
│ ├── domain/ # Business logic and models
│ │ ├── constants/ # App-wide constants
│ │ ├── di/ # Dependency injection and providers
│ │ │ └── providers/ # Riverpod providers by feature
│ │ ├── extensions/ # Dart extension methods
│ │ ├── io/ # Interface definitions
│ │ └── models/ # Data models and entities
│ ├── io/ # Data persistence layer
│ │ └── settings.dart # Settings implementation
│ ├── db/ # Database (Drift)
│ │ ├── repos/ # Repository implementations
│ │ ├── tables/ # Drift table definitions
│ │ └── database.dart # Database configuration
│ ├── ui/ # User interface
│ │ ├── screens/ # Feature screens
│ │ │ ├── home/ # Home screen
│ │ │ ├── currencies/ # Currency management
│ │ │ ├── units/ # Unit conversion
│ │ │ ├── settings/ # App settings
│ │ │ ├── debug/ # Debug screens
│ │ │ └── error/ # Error handling
│ │ └── widgets/ # Reusable UI components
│ ├── l10n/ # Localization
│ ├── utils/ # Utility functions
│ ├── config/ # App configuration
│ ├── theme.dart # Theme definitions
│ └── main.dart # Application entry point
├── test/ # Unit and widget tests
└── pubspec.yaml # Dependencies
Code Style Guidelines
Naming Conventions
| Type | Convention | Example |
|---|---|---|
| Classes & Widgets | PascalCase | CurrencyConverter |
| Variables & Functions | camelCase | fetchExchangeRates() |
| Files | snake_case | currency_converter.dart |
| Interfaces | Prefix with 'I' | ISettings |
| Constants | lowerCamelCase | defaultRefreshInterval |
Code Organization
- Imports: Grouped by functionality; package imports first, then project imports
- Widgets: Use composition over inheritance with small, focused components
- Error Handling: Dedicated error screens/widgets for specific scenarios
- Types: Use strong typing with required parameters where appropriate
Linting
The project enforces code quality through analysis_options.yaml:
- flutter_lints: Official Flutter lint rules
- riverpod_lint: Riverpod-specific lint rules
- custom_lint: Custom lint rule framework
Run linting with: flutter analyze
Development Commands
| Command | Purpose |
|---|---|
flutter clean && flutter pub get |
Reset dependencies |
flutter pub run build_runner build |
Generate code (Riverpod, Drift) |
flutter analyze |
Run static analysis |
flutter test |
Run all tests |
flutter test test/widget_test.dart |
Run single test file |
flutter build apk --release |
Build release APK |
./bin/install-wireless.sh |
Build and install to wireless device |
adb reverse tcp:3001 tcp:3001 |
Bridge ADB ports for API server |
Build Variants
CNVRT supports two build flavors:
Standard Build
- Includes Firebase Crashlytics for error reporting
- Suitable for Google Play Store and Apple App Store
- Build command:
flutter build apk --flavor standard --release
FOSS Build
- Excludes all proprietary libraries (Firebase, Google Services)
- Fully FOSS-compliant for F-Droid distribution
- No telemetry or remote crash reporting
- Build command:
flutter build apk --flavor foss --dart-define=FOSS_BUILD=true --release
See the FOSS Builds documentation for more details.
Localization
The app supports 5 languages:
- 🇬🇧 English (en)
- 🇪🇸 Spanish (es)
- 🇮🇹 Italian (it)
- 🇰🇷 Korean (ko)
- 🇨🇳 Chinese (zh)
Adding Translations
- Edit or create ARB files in
lib/l10n/(e.g.,app_en.arb,app_es.arb) - Regenerate localization code:
./bin/generate-i10n.shorflutter gen-l10n - Test translations by changing device language or using the in-app selector
Data Flow
- UI triggers an action (e.g., fetch currencies button pressed)
- Provider notifier executes business logic (validates, prepares request)
- Repository fetches data from remote API or local database
- Data flows back through providers to update application state
- UI rebuilds reactively with new state via Riverpod watchers