Skip to content
/ Hisab Public

Group expense splitting and settle-up app. Built with Flutter

License

Notifications You must be signed in to change notification settings

Zyzto/Hisab

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

256 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Hisab

Group expense splitting and settle-up app. Built with Flutter, Riverpod, GoRouter, and Supabase.

Features

  • Groups β€” Create groups (trips/events) with participants.
  • Expenses β€” Log multi-currency expenses with payer and split type (Equal, Parts, Amounts).
  • Balance β€” View who is owed / who owes; settle-up suggests minimal transfers.
  • Record Settlement β€” Tap a settlement suggestion to record the payment and zero out the debt.
  • Settings β€” Theme, language, and Local Only toggle.
  • Offline-first β€” Works entirely offline via local SQLite. Syncs directly with Supabase when online.

Two Modes

Mode What works Data location
Local-Only (default) Everything β€” full CRUD, settlement, no restrictions Local SQLite only
Online (with Supabase) Everything + invites, members, cross-device sync Supabase + local SQLite cache

When in Online mode and temporarily offline, you can still add expenses (queued for later sync). Other features like invites and member management require connectivity.

Screenshots

Details

Click to expand/hide

Install

🌐 Web / PWA

The app is deployed as a Progressive Web App (PWA) and is hosted on Firebase Hosting. New versions are deployed via the Release workflow (on version tags v* or manual run). It works locally and offline.

  • Install: Add to Home Screen via Chrome, Edge, or Safari.
  • Offline: Works perfectly without an internet connection.

Android

Option 1: Obtainium (Recommended) - Automatic Updates

Get it on Obtainium
  • Manual Setup: Install Obtainium from F-Droid or GitHub Releases, then:
    • Open Obtainium and tap the "+" button
    • Select "GitHub Releases" as the source
    • Enter repository: Zyzto/Hisab
  • Obtainium will automatically track new releases and notify you of updates

Option 2: Google Play Store WIP

  • Available on Google Play Store (when published)
  • Automatic updates through Play Store

Option 3: Direct Install (APK)

  • Download the APK (e.g. app-release.apk) from GitHub Releases
  • Enable "Install from unknown sources" in your Android settings
  • Tap the downloaded APK file to install

Requirements

  • Flutter SDK ^3.10.0
  • Dart ^3.10.0

Run

flutter pub get
dart run build_runner build --delete-conflicting-outputs
flutter run

Without --dart-define parameters the app runs in local-only mode (no sign-in, no sync).

Online mode

flutter run \
  --dart-define=SUPABASE_URL=https://xxxxx.supabase.co \
  --dart-define=SUPABASE_ANON_KEY=eyJhbGci...

For web: ensure web/sqlite3.wasm is present (it is generated locally and typically not committed). Generate it with:

dart run powersync:setup_web

Architecture

  • State β€” Riverpod 3 with riverpod_annotation codegen.
  • Navigation β€” GoRouter with ShellRoute and bottom nav.
  • Data β€” Repository pattern: IGroupRepository, IParticipantRepository, IExpenseRepository.
    • Local SQLite (via PowerSync package) is the single local database engine.
    • When online, writes go to Supabase first, then update local cache.
    • Reads always come from local SQLite for speed and reactivity.
    • Complex operations (invite accept, ownership transfer, etc.) use Supabase RPC functions.
  • Sync β€” DataSyncService handles: full fetch from Supabase, push pending offline writes, periodic refresh.
  • Auth β€” Supabase Auth (email/password, magic link, Google OAuth, GitHub OAuth).
  • Domain β€” lib/domain/: Group, Participant, Expense (amounts in cents), SplitType, SettlementTransaction, and related types (e.g. GroupMember, GroupInvite, SettlementMethod, SettlementSnapshot).

Supabase (optional)

For online mode, set up Supabase. See SUPABASE_SETUP.md for the full step-by-step guide covering:

  • Creating the Supabase project and applying database migrations
  • Configuring authentication providers (email, Google, GitHub)
  • Deploying Edge Functions (the repo includes invite-redirect; telemetry and send-notification are documented in setup docs and can be deployed from those definitions)
  • Configuring --dart-define parameters

If no --dart-define values are provided, the app runs in local-only mode β€” all features work except sign-in and cross-device sync.

Common issues

Issue Quick fix
App shows local-only mode Ensure both --dart-define params are set
SQLite web crash Run dart run powersync:setup_web to download WASM
OAuth redirect fails Check Supabase Auth redirect URLs match your app
Migration fails Ensure stable internet; migration is idempotent

Full configuration reference: CONFIGURATION.md.

Keeping secrets out of git

All secrets are provided at build time via --dart-define β€” nothing is committed to the repository. The only gitignored file for local secrets is lib/core/constants/app_secrets.dart (copy from app_secrets_example.dart); it holds the report-issue URL. All Supabase and Firebase values are provided via --dart-define only.

CI/CD (GitHub Actions)

The project includes a release workflow (.github/workflows/release.yml) that builds Android APK/AAB, deploys to Google Play, and deploys the web app to Firebase Hosting. It triggers on version tags (v*) or manual dispatch.

Required GitHub Secrets

Go to repo Settings β†’ Secrets and variables β†’ Actions and add each secret.

Supabase

Secret How to get it
SUPABASE_URL Supabase Dashboard β†’ Settings β†’ API β†’ Project URL
SUPABASE_ANON_KEY Supabase Dashboard β†’ Settings β†’ API β†’ anon public key
SITE_URL Your web app URL, e.g. https://hisab.shenepoy.com

Firebase Hosting

Secret How to get it
FIREBASE_SERVICE_ACCOUNT Firebase Console β†’ Project Settings β†’ Service accounts β†’ Generate new private key β†’ paste the entire JSON

Firebase / FCM (web push, optional for Android)

Secret How to get it
FCM_VAPID_KEY Firebase Console β†’ Project Settings β†’ Cloud Messaging β†’ Web Push certificates β†’ generate or copy the key pair's public key (required for web push token)

Android Signing

Generate a keystore (one-time setup):

keytool -genkey -v \
  -keystore ~/hisab-release.jks \
  -keyalg RSA -keysize 2048 \
  -validity 10000 \
  -alias hisab-release

You will be prompted for a store password and a key password (press Enter at the key password prompt to reuse the store password).

Then base64-encode it:

base64 -w 0 ~/hisab-release.jks

Copy the keystore into the project for local signed builds (already gitignored):

cp ~/hisab-release.jks android/app/release-keystore.jks
Secret Value
KEYSTORE_BASE64 Output of base64 -w 0 ~/hisab-release.jks (entire string, no newlines)
KEYSTORE_PASSWORD The store password you chose during keytool
KEY_ALIAS hisab-release
KEY_PASSWORD The key password (same as store password if you pressed Enter)
GOOGLE_SERVICES_JSON Base64-encoded android/app/google-services.json (Firebase Console β†’ Project settings β†’ your Android app β†’ download google-services.json, then base64 -w 0 android/app/google-services.json)

Google Play (optional)

Secret How to get it
PLAY_STORE_SERVICE_ACCOUNT_JSON Google Play Console β†’ Setup β†’ API access β†’ create/link a service account β†’ download JSON key

Local key.properties (for local release builds)

Create android/key.properties (gitignored):

storeFile=/absolute/path/to/android/app/release-keystore.jks
storePassword=your_store_password
keyAlias=hisab-release
keyPassword=your_key_password

Known issues

  • Change password modal β€” focus loss on text fields: The change-password sheet (Settings β†’ Change password) can lose focus on the current/new/confirm password fields at random when clicking (e.g. on the visibility toggles or elsewhere). In-app controls were made non-focusable (canRequestFocus: false) to reduce this, but the issue may still occur on some platforms or with certain focus/route updates. Workaround: tap directly on the text field again to refocus.

License

This project is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0).

  • You may share and adapt the material with attribution, for non-commercial use only, and you must share adaptations under the same license.
  • Full legal text: LICENSE in this repo, or legalcode on the CC site.
  • Human-readable summary: CC BY-NC-SA 4.0.

About

Group expense splitting and settle-up app. Built with Flutter

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages

 
 
 

Contributors