MVVM Architecture
The RideEase application follows the Model-View-ViewModel (MVVM) architectural pattern. This design ensures a clear separation of concerns, making the codebase easier to test, maintain, and scale. By leveraging Android Architecture Components like LiveData and ViewModel, the app maintains a reactive UI that responds to data changes automatically.
Architecture Overview
- Model: Represents the data layer and business logic (e.g., the
Usermodel and Firebase services). - View: The UI layer (Activities/Fragments) that displays data and sends user events to the ViewModel.
- ViewModel: Acts as a bridge, holding UI-related data in a lifecycle-conscious way and communicating with the Model/Repository.
Data Model
The User class is the primary data structure used across the authentication and profile modules.
User Model
Location: com.rideease.app.models.User
| Field | Type | Description |
| :--- | :--- | :--- |
| userId | String | Unique identifier from Firebase Auth. |
| userType | String | Type of user: "rider" or "driver". |
| fullName | String | The user's displayed name. |
| email | String | Registered email address. |
| phoneNumber | String | Verified phone number. |
| isPhoneVerified | boolean | Status of phone authentication. |
ViewModel Layer
ViewModels expose LiveData observers that the View (Activity) subscribes to. This ensures that UI updates only occur when the View is in an active state.
AuthViewModel
Manages email-based authentication and Firestore user document synchronization.
Public Methods:
signUpWithEmail(email, password, userType): Creates a new account and sends a verification email.signInWithEmail(email, password, userType): Authenticates existing users and validates their category (Rider/Driver).updateUserDetails(userId, fullName, phoneNumber): Persists additional profile information to Firestore.
Exposed LiveData:
| Method | Return Type | Purpose |
| :--- | :--- | :--- |
| getAuthResult() | LiveData<AuthResult> | Notifies the View of success/failure and the resulting userId. |
| getErrorMessage() | LiveData<String> | Streams human-readable error messages for UI Toast/Snackbars. |
| getUserProfile() | LiveData<User> | Provides current user data for profile rendering. |
UserDetailsViewModel
Handles phone-specific authentication logic, interfacing with the AuthRepository.
Public Methods:
startPhoneVerification(phoneNumber): Triggers the Firebase SMS code delivery.verifyPhoneCode(verificationId, code, userId, fullName, phoneNumber): Validates the OTP and updates the user's verification status.
View Layer (Implementation)
Activities in RideEase do not handle business logic. Instead, they observe ViewModel states and update the UI accordingly using ViewBinding.
Observing ViewModel State
To use a ViewModel in an Activity, initialize it via ViewModelProvider and observe its LiveData streams during onCreate.
Example: Login Logic in LoginActivity
// Initialize ViewModel
AuthViewModel viewModel = new ViewModelProvider(this).get(AuthViewModel.class);
// Observe Authentication Results
viewModel.getAuthResult().observe(this, authResult -> {
if (authResult.isSuccess()) {
// Navigate to Dashboard
startActivity(new Intent(this, MainActivity.class));
finish();
}
});
// Observe Errors
viewModel.getErrorMessage().observe(this, error -> {
Toast.makeText(this, error, Toast.LENGTH_LONG).show();
});
// Trigger Action
binding.loginButton.setOnClickListener(v -> {
viewModel.signInWithEmail(email, password, "rider");
});
Utilities and Repositories
While the ViewModel coordinates data, specific logic is abstracted into utility classes:
- AuthUtils: Contains static helper methods to check if a user has completed their profile setup (
checkUserDetails) or to validate if the current session matches the selected user type (isUserTypeValid). - AuthRepository: (Internal) Handles the direct interaction with Firebase Phone Auth callbacks, which is then piped into the
UserDetailsViewModel.
Key Benefits in RideEase
- Lifecycle Awareness: ViewModels survive configuration changes (like screen rotations), so authentication attempts aren't lost.
- Reactive UI: The UI automatically shows loading states or errors as soon as the
LiveDatain the ViewModel is updated. - Validation: ViewModels perform input validation (e.g., regex checks for phone numbers) before calling backend services, reducing unnecessary API calls.