Skip to content

Repository files navigation

Wallet

Wallet is a fully offline Android app for recording personal income and expenses. Data stays on the device; users can export a JSON-text backup and import it later without relying on a hosted service.

The app currently targets Android API 34 and supports Android 5.0 (API 21) and above.

What the app does

  • Add positive or negative wallet entries with an amount, details, and date/time.
  • Edit, clone, delete, or copy an entry's details.
  • Search details and amounts, including numeric searches such as 123 or -123.
  • Filter entries with a precise From/To date and time range.
  • Order results by date or amount.
  • Hide the total balance for privacy.
  • Select 12-hour or 24-hour time from the overflow menu.
  • Export and import local backups.

Project layout

app/
  src/main/java/com/example/abdul/bank/
    MainActivity.java          Main list, filters, search, import/export entry points
    AddOrSubtract.java         Create and edit transactions
    DBHelper.java              Compatibility/repository facade used by UI code
    SPManager.java             User preferences (filters, ordering, privacy, time format)
    data/
      WalletEntity.java        Room mapping for the legacy Wallet table
      WalletDao.java           Room data access methods
      WalletDatabase.java      Room singleton and migrations
    common/utils/DateUtil.java Date/time display formatting
  src/main/res/                Layouts, strings, icons, menus, styles
  src/androidTest/             On-device Room migration tests
  schemas/                     Exported Room schema JSON

Build and run

Requirements:

  • JDK 17
  • Android SDK with API 34 installed
  • An emulator or Android device for instrumentation tests

Windows commands:

$env:JAVA_HOME='C:\Program Files\Java\jdk-17'
$env:Path="$env:JAVA_HOME\bin;$env:Path"

.\gradlew.bat assembleDebug
.\gradlew.bat testDebugUnitTest
.\gradlew.bat connectedDebugAndroidTest # requires a connected device/emulator
.\gradlew.bat assembleRelease

Debug APK output:

app/build/outputs/apk/debug/app-debug.apk

The release build produced by this repository is unsigned unless a release signing configuration is supplied.

Data model and compatibility rules

The database is deliberately compatibility-sensitive. Existing users may already have data in the original SQLite database.

  • Database file name: wallet.db
  • Current database version: 2
  • Table name: Wallet
  • Canonical columns: _id, Date, DateLong, Amount, Details
  • DateLong is an epoch-millisecond value and is the authoritative transaction timestamp.
  • Room uses the same table, columns, and version so it can adopt an installed version-2 database without replacing rows.

Do not break these rules

When changing persistence code:

  1. Never rename wallet.db, Wallet, or existing columns without a migration.
  2. Never add fallbackToDestructiveMigration().
  3. Never use DROP TABLE as an upgrade strategy.
  4. Increase the Room version for every schema change.
  5. Add an explicit Room migration and an instrumentation test for every new version path.
  6. Keep exported schema JSON under app/schemas/ up to date.

WalletDatabaseMigrationTest creates real legacy version-1 and version-2 databases, then opens them with Room. It verifies that IDs and transaction values survive migration/adoption.

Version 1 note

Version 1 did not contain DateLong; it only stored a formatted local date string. The 1 -> 2 migration parses that string in the current locale/timezone where possible. If it cannot parse a date, the row is retained and DateLong remains null. This is unavoidable because the old format did not store a timezone or an absolute timestamp.

Time behavior

Transaction timestamps are stored as epoch milliseconds. The app displays an entry in the device's current timezone, preserving absolute-instant behavior.

The overflow menu includes Use 24-hour time. Its preference is persisted and controls:

  • Entry dates in the list
  • From/To filter labels and pickers
  • Create/edit date display and time picker
  • Result-summary dates

The backup filename remains a filesystem-safe technical timestamp.

Search and ordering

Search settings and ordering are stored in SharedPreferences through SPManager.

  • Details phrase / keyword modes use LIKE matching.
  • A fully parseable number also searches the amount column. For example, 123 matches both 123 and -123 because amount matching uses the existing “contains” behavior.
  • The six order choices cover newest/oldest date, signed high/low amount, and largest/smallest absolute amount magnitude.

SQL parameters are bound with SimpleSQLiteQuery; do not return to string-concatenated user search queries.

Backup format

Exports are JSON arrays written to a .json.txt file. Each current record contains:

{
  "date_string": "08-Aug-2026 04:44 AM",
  "date_long": 1786160640000,
  "amount": -1250,
  "details": "Groceries"
}

Import and export use Android's system document picker on every supported Android version. They do not require storage permissions or direct filesystem paths. Backup text is written and read as UTF-8, and imports are limited to 10 MB while reading.

Current exports intentionally omit _id. Older backup files that contain _id remain compatible because imports ignore it. Each imported entry receives a new local ID, avoiding primary-key collisions when adding backup entries alongside current entries. Imports are currently additive; the restore-choice workflow remains future work. date_long is the value used by the app after import.

UI conventions

  • Keep data-entry actions clear and compact; the primary screen is designed for frequent use.
  • Preserve at least 48dp targets for normal screen controls. Compact dialog actions are an intentional exception where several actions must remain visible.
  • The entry-details dialog prioritizes a scrollable details area over actions.
  • Use string resources for all user-visible text.
  • A zero amount is allowed. Its success toast is simply Saved, because +0 and -0 are misleading.

Guidance for AI agents and contributors

Before changing code:

  1. Check git status and preserve unrelated worktree changes.
  2. Search call sites before changing a shared helper or database API.
  3. Keep DBHelper compatible unless intentionally refactoring every caller.
  4. Avoid changing backup semantics without a backward-compatible import path.
  5. Prefer small, focused UI changes over visual redesigns that make common actions slower.
  6. For database work, run the instrumentation migration tests on an emulator/device before handoff.

For normal UI-only work, a focused debug build is usually sufficient:

.\gradlew.bat assembleDebug

TODO / Future work

  • Support for Fractional point amounts.
  • Should there be difference a b/w date-created and date-of-transaction? If yes, then we need to add a new column for date-created and make it non-nullable with default value as current timestamp. And then we will have to update the import/export logic to support this new column.
  • Scan for any memory leaks in this app. dont make any changes yet.
  • Add optional Google Drive backup to the user's own Google account, using app-scoped Drive storage rather than a central server.
  • Let users choose a backup file from a list during restore and explicitly choose whether to replace current entries or add imported entries.
  • Consider removing the legacy Date column in a dedicated, tested Room migration; DateLong is already the canonical timestamp.
  • Move database operations off the main thread while retaining the current UI behavior.
  • Improve the Import/Export behavior like stream import/export and progress feedback for large backups. For this we might need to introduce versioning in Import/Export options. Like latest app is exporting a v2 variant of backup files so that import option will then ask the user to choose which version of the backup file you are importing? And to support streaming backup files we will have to move towards jsonl-file-type kind of approach.
  • Add focused UI tests for import/restore, ordering, time-format switching, and the privacy toggle.
  • Speech-to-text for details entry. If possible, also detect the amount from the speech input.
  • Detect micro-finance app notifications with the user-defined text pattern and which apps' notifications to apply listener to, and automatically add a wallet entry with the amount and details from the notification description.
  • A better icon for the app.
  • Floating button for an entry.

About

Maintain a history of your regular expenses.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages