jxareas/Xpensor
49.5
Weak · 21 September 2026
5.2k
lines of production code
Kotlin
primary language
4
measurements over time
What this system is
This is an Android financial tracking application that allows users to manage bank accounts, record and categorize transactions, and convert currencies. The system provides a complete data layer using Room and shared preferences for local persistence, supported by a Hilt-based dependency injection architecture. It features a modern, reactive UI with view models handling state for accounts, transactions, charts, and currency conversion.
How it got here
2022 — MVVM architecture and feature implementation
26 changes.
The project underwent a significant architectural shift to a modern MVVM structure using Hilt for dependency injection and Kotlin DSL for build configuration. This period focused on implementing core features, including transaction and account management, currency conversion, and date selection, while establishing a robust local data layer with Room.
2023 — Data layer and test coverage expansion
9 changes.
This period focused on implementing the repository pattern for accounts, transactions, and currency conversion, establishing a robust data access layer. Concurrently, significant effort was dedicated to increasing test coverage by adding unit tests for various ViewModels and instrumentation tests for database operations.
Features
Add SelectDateMenu component for date selection UI
A new SelectDateMenu class has been added to the date feature's presentation layer. This component implements the SingleToolbarItemMenuProvider interface to handle toolbar item clicks for the date selection menu, linking the UI to the corresponding menu resource and click callback.
app/src/main/java/com/jxareas/xpensor/features/date/presentation/ui/menu · high confidence
Add currency converter UI and state management
Users can now convert currencies through a new interface that displays loading, success, and error states. The implementation introduces a ConversionState sealed class to manage UI states (Idle, Loading, Ready, Error) and a ConverterFragment that binds to a ConverterViewModel. The ViewModel handles the conversion logic via a use case, emitting events for UI updates and user interactions like swapping currencies or triggering conversion.
app/src/main/java/com/jxareas/xpensor/features/converter/presentation · high confidence
Add date selection UI and ViewModel
The app introduces a new date selection interface via DateSelectorDialogFragment and its corresponding DateSelectorViewModel. Users can now choose specific dates, today, the past week, month, year, or all-time ranges through a dialog that integrates with the app's main state via the MainViewModel. The implementation uses Kotlin Coroutines Channels for event emission and lifecycle-aware flow collection to manage the date selection logic.
app/src/main/java/com/jxareas/xpensor/features/date/presentation/ui · high confidence
Add pre-commit and pre-push hooks for automated Kotlin linting
The repository now includes a pre-commit hook that automatically runs ktlint on staged Kotlin files and stages the formatted results, as well as a pre-push hook that executes both ktlint and detekt static analysis checks. A new Python script is also added to combine ktlint, detekt, and lint XML reports into a single report file, streamlining the process of aggregating static analysis results across multiple modules (app, database, analytics).
hooks, scripts · high confidence
Add shared-test module with mock data and test utilities
A new shared-test module has been introduced to centralize test utilities and mock data. This includes a TestCoroutineRule for managing coroutine dispatchers in tests, and mock data generators for Account, Category, and Transaction entities and domain models, enabling consistent test fixtures across the application.
shared-test · high confidence
Add transaction creation and category selection UI components
The app now includes the UI for adding a new transaction and selecting a category. Users can create a new transaction via a bottom sheet that validates inputs and handles navigation back to the main transaction list. Additionally, a new bottom sheet allows users to browse and select a category for their transaction, with the list updating based on the selected account and date range.
app/src/main/java/com/jxareas/xpensor/features/transactions/presentation/ui/actions · high confidence
Adds Hilt dependency injection module for application context and database
A new Hilt AppModule is introduced to provide the application Context and the XpensorDatabase instance as singletons. This establishes the foundational dependency injection bindings for the app's core data layer.
app/src/main/java/com/jxareas/xpensor/di · high confidence
Introduce Chart and Settings screens with lifecycle-aware data binding
Users can now view a pie chart of their expenses by category and access the app's settings. The Chart screen displays a dynamic pie chart that updates based on the selected date range and account, using lifecycle-aware coroutines to ensure data collection is tied to the fragment's lifecycle. The Settings screen allows users to toggle between light and dark themes, with the change applied immediately. These new screens are built using the MVVM pattern, with the ChartViewModel managing state and events via Kotlin Flows and Channels.
app/src/main/java/com/jxareas/xpensor/features/chart · high confidence
Introduce PIN-based authentication flow
Users can now set, enter, and verify a 4-digit PIN code to access the app. The new AuthenticationActivity handles the PIN entry UI, while domain use cases manage storing and retrieving the PIN from shared preferences. The flow supports first-time setup, subsequent login, and a 'forgot PIN' option that erases app data.
app/src/main/java/com/jxareas/xpensor/features/authentication · high confidence
Introduce Transactions list and management UI
A new TransactionsFragment and TransactionsViewModel have been added to the app, providing the user interface for viewing a list of transactions, selecting date ranges and accounts, and managing individual transactions (including deletion confirmation dialogs). The implementation uses Kotlin Coroutines with lifecycle-aware flow collection to manage state and events, and integrates with the existing navigation and bottom navigation components.
app/src/main/java/com/jxareas/xpensor/features/transactions/presentation/ui · high confidence
Introduce local data layer for transactions and categories
The app now uses a new local data storage structure for transactions and categories, introducing Room DAOs (CategoryDao, TransactionDao) and corresponding local data sources (CategoryLocalDataSource, TransactionLocalDataSource) to manage local persistence. This includes new view models for aggregating transaction amounts by category and day, enabling the app to retrieve and display transaction history and category summaries from the local database.
app/src/main/java/com/jxareas/xpensor/features/transactions/data/local · high confidence
Introduce main screen UI and state management
The app's main screen now features a new MainActivity and MainViewModel that handle navigation, toolbar updates, and user interactions. The ViewModel manages state for accounts, selected account, and date range, while the Activity sets up navigation, listeners, and event collectors to update the UI accordingly.
app/src/main/java/com/jxareas/xpensor/core/presentation · medium confidence
Introduce new Accounts feature UI and ViewModel architecture
The accounts presentation layer has been refactored to use a modern, reactive architecture. The \AccountsFragment\ and \AccountsViewModel\ now use \repeatOnLifecycle\ and \flowWithLifecycle\ for robust coroutine-based state management. A new \AccountUi\ model and corresponding mappers replace the previous domain model usage, allowing the UI to handle UI-specific concerns like color and formatting. The \AccountActionsBottomSheet\ and \AccountActionsViewModel\ provide a bottom sheet for account actions, while \AddAccountFragment\ and \EditAccountFragment\ handle creation and editing. The \AccountFilterDialogFragment\ allows users to filter and select accounts. All these components are wired together using Hilt for dependency injection.
app/src/main/java/com/jxareas/xpensor/features/accounts/presentation · high confidence
Introduces Hilt dependency injection modules for core app features
The app now uses Hilt to manage dependencies for accounts, categories, transactions, currency conversion, and user preferences. New DI modules (AccountModule, CategoryModule, TransactionModule, CurrencyConverterModule, PreferencesModule) bind repositories, data sources, and DAOs to their implementations, while NetworkModule configures the HTTP client with an authentication interceptor and Moshi JSON parsing. This change enables the application to inject these services throughout the codebase, supporting the new features for managing accounts, transactions, and currency conversion.
app/src/main/java/com/jxareas/xpensor/di/modules · high confidence
Introduces common utility classes and extension functions for Android and Kotlin
The app adds a suite of new utility classes and extension functions in the common module to streamline development. This includes a sealed \Resource\ class for handling data states, functional interfaces for view binding and toolbar clicks, and Kotlin extension functions for \Flow\, \Fragment\, \ImageView\, \View\, and \ViewModel\. These additions provide reusable helpers for tasks like displaying toasts, managing menu providers, and handling coroutine scopes.
app/src/main/java/com/jxareas/xpensor/common · high confidence
Introduces domain models and repository interface for currency conversion
The converter feature's domain layer now includes new domain models and a repository interface to support currency conversion logic. Specifically, a \BaseCurrency\ value class and a \Currencies\ enum (listing USD, EUR, NIO, CRC, and GBP) have been added to represent currency data. Additionally, a \CurrencyRepository\ interface has been introduced, defining a \getCurrencyRates\ method that returns a \Resource\<CurrencyComparison\>\, establishing the contract for fetching currency data within the application's architecture.
app/src/main/java/com/jxareas/xpensor/features/converter/domain · high confidence
Introduces domain-layer abstractions for account management
The app now defines a formal domain layer for the accounts feature, introducing an AccountRepository interface and a set of use cases (AddAccount, DeleteAccount, GetAccounts, GetTotalAccountsAmount, and UpdateAccount) that encapsulate the logic for creating, reading, updating, and deleting accounts. This structure provides a clean, testable interface for the rest of the application to interact with account data.
app/src/main/java/com/jxareas/xpensor/features/accounts/domain · high confidence
Introduces local data storage and user preferences
The app now supports local data persistence using the Room database, with new components for date and time conversion, a generic Room-based data source, and a UserPreferences interface backed by SharedPreferences to store user settings like theme and currency.
app/src/main/java/com/jxareas/xpensor/core/data · high confidence
New data layer for currency conversion
The app introduces a complete data layer for the currency converter feature, including a Retrofit API interface for the FreeCurrencyApi, an OkHttp interceptor for API key authentication, and a remote data source that fetches live exchange rates. A new CurrencyDataMapper converts remote DTOs into domain models, while DefaultCurrencyRepository implements CurrencyRepository to handle network calls and map responses to a Resource wrapper, enabling the feature to retrieve and display up-to-date currency comparisons.
app/src/main/java/com/jxareas/xpensor/features/converter/data · high confidence
New transaction list adapter with day and item views
The transactions screen now uses a new RecyclerView adapter that renders two distinct item types: a header for each day and individual transaction cards. The adapter is wired with UserPreferences to display the user's preferred currency and formatting, and the diff callback handles change detection for both TransactionByDay and TransactionDetails models.
app/src/main/java/com/jxareas/xpensor/features/transactions/presentation/ui/adapter · high confidence
Behavioural changes
4 commits (0 fixes) modifying app/src/main/assets
A change to existing behaviour in app/src/main/assets — 4 commits, 2 files.
app/src/main/assets · medium confidence · unverified
App-level theme initialization and removal of legacy Activity
The application now initializes the global dark/light mode setting at startup by reading the user's preferred theme from the new UserPreferences service and applying it via AppCompatDelegate. This replaces the previous approach where the MainActivity directly managed the theme, as the old MainActivity class has been removed.
app/src/main/java/com/jxareas/xpensor · high confidence
Centralized build configuration and dependency management
The project has introduced a centralized build configuration in the \buildSrc\ directory, consolidating version numbers, plugin IDs, and dependency coordinates into Kotlin objects (\Versions\, \Dependencies\, \BuildPlugins\, \ProjectProperties\). This change standardizes the versions of core Android libraries (such as Kotlin, Room, Hilt, and Jetpack components) and tooling plugins (such as KtLint, Detekt, and the Versions plugin), making it easier to update library versions in a single location.
buildSrc · high confidence
Implement transaction and category data access with repository pattern
Users can now view and manage their financial records more reliably. This change introduces the data layer for transactions and categories, implementing the repository pattern to fetch transaction details, category summaries, and daily totals. By replacing the previous mapper classes with extension functions and wiring them into the new DefaultTransactionRepository and DefaultCategoryRepository, the app ensures consistent data mapping from the local database to the domain models, which helps prevent crashes when loading all-time transaction lists.
app/src/main/java/com/jxareas/xpensor/features/transactions/data/repository · medium confidence
Implemented DefaultAccountRepository with local data source integration
The account repository layer now uses a new DefaultAccountRepository class that delegates all operations to an AccountLocalDataSource. This change introduces a concrete implementation of the AccountRepository interface, mapping domain models to local entities via extension functions (toAccountEntity, toAccountWithDetails) for all CRUD operations including getAccounts, getTotalAccountsAmount, getAccountById, insert, update, and delete.
app/src/main/java/com/jxareas/xpensor/features/accounts/data/repository · medium confidence
Introduce local data source for account management
Added new local data source components for the accounts feature, including the AccountDao interface for Room database operations, the AccountLocalDataSource interface defining the local data access contract, and the AccountRoomLocalDataSource implementation that bridges the DAO to the data layer. This provides the foundation for storing and retrieving account information locally.
app/src/main/java/com/jxareas/xpensor/features/accounts/data/local · medium confidence
Introduces account data mapping between domain and local entities
A new mapper is added to convert between the local database entity (AccountEntity) and the domain model (Account), including a method to map with details. This change supports the internal data layer by providing explicit conversion logic for account data, ensuring consistent transformation between storage and domain representations.
app/src/main/java/com/jxareas/xpensor/features/accounts/data/mapper · medium confidence
Refactor transaction domain layer with new repository interfaces and use cases
The transaction domain layer has been restructured to introduce explicit repository interfaces (CategoryRepository and TransactionRepository) and dedicated use cases (AddTransactionUseCase, DeleteTransactionUseCase, GetCategoriesUseCase, GetTransactionsUseCase, GetTransactionsWithDayUseCase, and ValidateTransactionUseCase). This change introduces a cleaner separation of concerns by moving data access logic into repository interfaces and encapsulating business rules within use cases, improving maintainability and testability of the transaction feature.
app/src/main/java/com/jxareas/xpensor/features/transactions/domain · high confidence
Transaction category mapping refactored to extension functions
The mapping logic for transaction categories has been refactored from traditional mapper classes to Kotlin extension functions. This change introduces new extension functions on domain and UI model classes (such as Category, CategoryWithDetails, and their UI counterparts) to handle conversions between entities, domain models, and presentation models. Users will see no functional change, but the underlying implementation is now more concise and idiomatic.
app/src/main/java/com/jxareas/xpensor/features/transactions/presentation/mapper · high confidence
Updated ProGuard rules comment to reference Kotlin build script
The comment in the ProGuard rules file was updated to reflect the migration from Groovy to Kotlin for the build script, changing the reference from 'build.gradle' to 'build.gradle.kts'.
app · high confidence
Test coverage
Added empty unit test structures for MainViewModel and AuthenticationViewModel; Added instrumentation tests for local database DAOs; Added unit tests for account feature ViewModels; Added unit tests for multiple ViewModels.
Dependencies
Migrate Android build scripts from Groovy to Kotlin DSL
The project's Gradle build configuration has been migrated from Groovy (.gradle) to Kotlin DSL (.gradle.kts) files. This includes the top-level build.gradle, the app module's build.gradle, and the settings file. The migration introduces a centralized buildSrc module to manage dependencies and plugins, adds a shared test module for common testing dependencies, and configures tools like Detekt and KtLint. Additionally, the JitPack repository is added to support third-party libraries like MPAndroidChart.
(dependencies) · high confidence
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
How this codebase got here
Score
- CAI 56 → 49 (-6.3)
- Rubric changed (rubric-2026.08.19 → rubric-2026.09.15) — scores are not directly comparable.
Lenses
- Code Health 99 → 99 (-0.2)
- Architecture 100 → 75 (-24.5)
- Maturity 65 → 61 (-4.1)
- Readiness 24 → 26 (+1.4)
- Security 97 → 97 (+0.0)
- Domain Modelling 100 → 70 (-30.3)
Resolved (8)
- Coverage not included — suite not readable by the collector
- Dependency hygiene not measured — dependency manifest found but not parsed for hygiene
- Duplicated block (6 lines × 2) (app/src/main/java/com/jxareas/xpensor/features/accounts/presentation/ui/actions/add/AddAccountFragment.kt)
- Duplicated block (7 lines × 2) (app/src/main/java/com/jxareas/xpensor/features/accounts/presentation/ui/actions/add/AddAccountFragment.kt)
- Duplicated block (9 lines × 3) (app/src/main/java/com/jxareas/xpensor/features/accounts/presentation/ui/AccountsFragment.kt)
- No exposed public API
- Test reliability not included
- single-maintainer — knowledge-concentration (bus factor) risk
New (12)
- Dependency hygiene PARTLY measured — Maven/Gradle declarations read, no dependency graph resolved
- Documentation: no installation or build instructions (README.md)
- Documentation: no licence statement (README.md)
- Documentation: no usage examples (README.md)
- Duplicated block (10 lines × 2) (app/src/main/java/com/jxareas/xpensor/features/accounts/presentation/ui/AccountsViewModel.kt)
- Duplicated block (11 lines × 4) (app/src/main/java/com/jxareas/xpensor/features/accounts/presentation/ui/AccountsFragment.kt)
- Duplicated block (5 lines × 2) (app/src/main/java/com/jxareas/xpensor/features/accounts/presentation/ui/actions/add/AddAccountFragment.kt)
- Duplicated block (5 lines × 2) (app/src/main/java/com/jxareas/xpensor/features/accounts/presentation/ui/actions/add/AddAccountFragment.kt)
- Duplicated block (6 lines × 2) (app/src/main/java/com/jxareas/xpensor/features/accounts/presentation/ui/actions/add/AddAccountFragment.kt)
- Duplicated block (7 lines × 2) (app/src/main/java/com/jxareas/xpensor/features/accounts/presentation/ui/AccountsViewModel.kt)
- Members sharing a duplicated core (4 members, 50+ identical tokens) (app/src/main/java/com/jxareas/xpensor/features/accounts/presentation/ui/AccountsFragment.kt)
- TodoComment (app/src/main/java/com/jxareas/xpensor/features/converter/presentation/ui/ConverterFragment.kt)
Architecture
- Containers 0 added · 0 removed · contexts 1 added · 1 removed · edges 0 added · 0 removed
Added bounded contexts (1)
- app
Removed bounded contexts (1)
- shared-test
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
Survey your own repository
jxareas/Xpensor was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.
About this page
- The score is its most recent published measurement, taken on 21 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
- Measured at commit c8639526a7fdd710e485668093ce627e0fa1e8e5 — the exact code this score is about.
- Scored under rubric-2026.09.15 — the same rubric and the same method as every other entry in this index.
- Measured by watchdog.canine.dev using codehealth-analyzer preprod-fa71c66cabd8.