Skip to content
CAI
Software that uses CAICheck a score

jxareas/Xpensor

49.5

Weak · 21 September 2026

5.2k

lines of production code

Kotlin

primary language

4

measurements over time

CAI band scale
CAI trend line
CAI lens gauges

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.