Skip to main content
The EV Sum 2 codebase follows a feature-based, layered organization that mirrors the architectural design. This structure makes it easy to locate files and understand the system’s organization.

Root structure

app/src/main/java/com/demodogo/ev_sum_2/
├── data/           # Data layer - Repositories and Firebase
├── domain/         # Domain layer - Models and business logic
├── services/       # Service layer - Coordination and hardware
├── ui/             # UI layer - Jetpack Compose screens
└── MainActivity.kt # Application entry point
The package name com.demodogo.ev_sum_2 represents the application identifier. All code is organized under this namespace.

Data layer

The data layer contains all code related to data access and persistence:
data/
├── firebase/
│   └── FirebaseModule.kt      # Firebase initialization
├── repositories/
│   ├── AuthRepository.kt      # Authentication data access
│   ├── PhraseRepository.kt    # Phrase CRUD operations
│   ├── LocationRepository.kt  # Geolocation data access
│   └── UserRepository.kt      # User data management
├── session/
│   └── SessionStore.kt        # Session persistence
├── ThemeStore.kt              # Theme preferences
├── UserStore.kt               # User preferences
└── Validators.kt              # Data validation utilities

Key files

Initializes Firebase services and provides singleton instances of FirebaseAuth and FirebaseFirestore.Purpose: Centralized Firebase configuration
Dependencies: Firebase SDK
Manages Firebase Authentication operations including login, registration, password reset, and session state.Key methods:
  • suspend fun login(email: String, password: String)
  • suspend fun register(email: String, password: String)
  • fun authStateFlow(): Flow<FirebaseUser?>
Location: data/repositories/AuthRepository.kt:1
Handles CRUD operations for phrases in Firestore. Automatically scopes data to the current user’s UID.Key methods:
  • suspend fun add(text: String)
  • suspend fun get(): List<Phrase>
  • suspend fun update(id: String, newText: String)
  • suspend fun delete(id: String)
Location: data/repositories/PhraseRepository.kt:1
Wraps Google Play Services FusedLocationProviderClient to access device GPS coordinates.Key methods:
  • fun hasPermission(): Boolean
  • suspend fun getLatLng(): Pair<Double, Double>
Uses DataStore Preferences API for local key-value storage. Stores session-related data.

Domain layer

The domain layer contains pure Kotlin code with no Android or Firebase dependencies:
domain/
├── errors/
│   ├── AppException.kt        # Base exception class
│   ├── AuthException.kt       # Authentication errors
│   └── DataException.kt       # Data operation errors
├── models/
│   ├── AppUser.kt             # User domain model
│   ├── Phrase.kt              # Phrase domain model
│   ├── DeviceLocation.kt      # Location coordinates model
│   ├── Message.kt             # UI message model
│   └── DictationTarget.kt     # Speech input target enum
└── validators/
    ├── SpeechNormalization.kt # Speech-to-text normalization
    └── Validators.kt          # Input validation functions

Key files

Represents a user-created phrase with metadata.
data class Phrase(
    val id: String = "",
    val text: String = "",
    val createdAtMillis: Long = 0L
)
Location: domain/models/Phrase.kt:1
Represents GPS coordinates.
data class DeviceLocation(
    val latitude: Double,
    val longitude: Double
)
Contains algorithms for converting spoken Spanish to text suitable for email/password fields.Key functions:
  • normalizeEmailFromSpeech(input: String): String
  • normalizePasswordFromSpeech(input: String): String
Transforms:
  • “arroba” → ”@”
  • “punto” → ”.”
  • “guion bajo” → ”_”
  • “uno” → “1”
Location: domain/validators/SpeechNormalization.kt:1
Domain-specific exception classes for error handling throughout the application.
The domain layer can be tested with standard JUnit without requiring the Android framework or Firebase emulators.

Service layer

The service layer coordinates between UI and data, and controls device hardware:
services/
├── AuthService.kt             # Authentication coordination
├── PhraseService.kt           # Phrase business logic
├── UserService.kt             # User management
├── LocationService.kt         # Location + geocoding
├── SpeechController.kt        # Speech recognition control
└── TextToSpeechController.kt  # TTS control

Key files

Orchestrates authentication flow with error mapping.Key methods:
  • suspend fun login(email: String, password: String)
  • suspend fun register(email: String, password: String)
  • suspend fun recover(email: String)
  • fun authStateFlow(): Flow<FirebaseUser?>
Location: services/AuthService.kt:1
Combines GPS coordinates with reverse geocoding to provide location + address.Key methods:
  • fun hasPermission(): Boolean
  • suspend fun getLocationWithAddress(): LocationResult
  • private suspend fun reverseGeocodeSafe(lat: Double, lon: Double): String?
Handles: API level differences for Android 13+ Geocoder callbacks
Location: services/LocationService.kt:1
Wraps Android’s SpeechRecognizer for voice input.Key methods:
  • fun setListener(onReady, onPartial, onFinal, onError, onEnd)
  • fun start()
  • fun stop()
  • fun destroy()
Locale: Spanish (Chile) - “es-CL”
Location: services/SpeechController.kt:1
Controls Android’s TTS engine for accessibility.Key methods:
  • fun speak(text: String)
  • fun stop()
  • fun destroy()
Configuration: Uses QUEUE_FLUSH to prevent audio overlap
Location: services/TextToSpeechController.kt:1

UI layer

The UI layer is built entirely with Jetpack Compose and organized by feature:
ui/
├── auth/
│   ├── LoginScreen.kt         # Login with email/password
│   ├── RegisterScreen.kt      # Account creation
│   └── RecoverScreen.kt       # Password recovery
├── home/
│   └── HomeScreen.kt          # Main dashboard with phrase CRUD
├── location/
│   └── DeviceLocationScreen.kt # GPS coordinates + address
├── nav/
│   ├── AppNavGraph.kt         # Navigation graph definition
│   ├── RouterScreen.kt        # Authentication routing
│   └── AppRoutes.kt           # Route constants
└── theme/
    ├── Theme.kt               # Material3 theme configuration
    ├── Color.kt               # Color palette
    └── Type.kt                # Typography definitions
The app uses Jetpack Navigation Compose with a router pattern for authentication-aware navigation.

AppRoutes.kt

Defines route constants:
object AppRoutes {
    const val LOGIN = "login"
    const val REGISTER = "register"
    const val RECOVER = "recover"
    const val HOME = "home"
    const val LOCATION = "location"
}

AppNavGraph.kt

Defines the navigation graph with reactive authentication state: Key features:
  • Reactive authentication state using authStateFlow().collectAsState()
  • Automatic redirection based on login status
  • Proper back stack management with popUpTo
Location: ui/nav/AppNavGraph.kt:1

RouterScreen.kt

Handles automatic navigation based on authentication state:
@Composable
fun RouterScreen(
    isLoggedIn: Boolean,
    onGoHome: () -> Unit,
    onGoLogin: () -> Unit
) {
    LaunchedEffect(isLoggedIn) {
        if (isLoggedIn) onGoHome() else onGoLogin()
    }
    // Loading indicator while deciding route
}

Screen components

LoginScreen.kt
  • Email and password input fields
  • Voice dictation for email/password
  • Speech normalization integration
  • Navigation to register/recover screens
RegisterScreen.kt
  • New account creation
  • Password confirmation
  • Voice input support
RecoverScreen.kt
  • Password reset email
  • Firebase sendPasswordResetEmail integration

Testing structure

app/src/test/java/com/demodogo/ev_sum_2/
├── domain/
│   └── validators/
│       └── SpeechNormalizersTest.kt  # Unit tests for speech normalization
└── ExampleUnitTest.kt

app/src/androidTest/java/com/demodogo/ev_sum_2/
└── ExampleInstrumentedTest.kt

SpeechNormalizersTest.kt

Comprehensive test suite for speech-to-text normalization:

Email normalization tests

Tests conversion of spoken email addresses including “arroba”, “punto”, and numeric spellings

Password normalization tests

Validates password input from voice with special characters and numbers

Edge cases

Tests spacing, special characters, and phonetic variations

100% coverage

Ensures all normalization paths are validated
Location: app/src/test/java/com/demodogo/ev_sum_2/domain/validators/SpeechNormalizersTest.kt:1

Configuration files

Build configuration

app/
├── build.gradle.kts           # App-level Gradle configuration
└── google-services.json       # Firebase project configuration (gitignored)

build.gradle.kts               # Project-level Gradle configuration

Key dependencies (build.gradle.kts)

implementation("androidx.activity:activity-compose:1.9.2")
implementation("androidx.compose.material3:material3:1.3.0")
implementation("androidx.compose.material:material-icons-extended:1.7.6")
implementation(platform(libs.androidx.compose.bom))
SDK versions:
  • compileSdk = 36
  • minSdk = 24
  • targetSdk = 36
  • Kotlin JVM target: 11

Manifest configuration

Required permissions declared in AndroidManifest.xml:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
All permissions are requested at runtime. The app handles denied permissions gracefully.

File naming conventions

Screens

FeatureScreen.kt (e.g., LoginScreen.kt, HomeScreen.kt)

Repositories

EntityRepository.kt (e.g., AuthRepository.kt, PhraseRepository.kt)

Services

EntityService.kt or FeatureController.kt

Models

EntityName.kt (e.g., Phrase.kt, AppUser.kt)

Tests

ClassNameTest.kt (e.g., SpeechNormalizersTest.kt)

Package organization principles

1

Layer-first organization

Top-level packages represent architectural layers (data, domain, services, ui)
2

Feature grouping within UI

UI components are grouped by feature (auth, home, location)
3

Shared utilities at layer root

Common utilities live at the root of their layer (e.g., data/Validators.kt)
4

Consistent naming

File names clearly indicate their role (Repository, Service, Screen, Controller)

Quick reference

Use this guide to quickly locate specific functionality:
FeatureLayerFile
User loginDatadata/repositories/AuthRepository.kt:15
Login UIUIui/auth/LoginScreen.kt
Login coordinationServicesservices/AuthService.kt:11
Phrase CRUDDatadata/repositories/PhraseRepository.kt:17
GPS locationDatadata/repositories/LocationRepository.kt
Reverse geocodingServicesservices/LocationService.kt:39
Voice recognitionServicesservices/SpeechController.kt:54
Speech normalizationDomaindomain/validators/SpeechNormalization.kt:4
Text-to-speechServicesservices/TextToSpeechController.kt:20
Navigation graphUIui/nav/AppNavGraph.kt:19
Theme configurationUIui/theme/Theme.kt
Firebase initDatadata/firebase/FirebaseModule.kt

Next steps

Architecture overview

Review the high-level architecture and design principles

Service-Repository pattern

Learn about the architectural pattern implementation

Build docs developers (and LLMs) love