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

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). 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. 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.
  • SyncDataSyncService handles: full fetch from Supabase, push pending offline writes, periodic refresh.
  • Auth — Supabase Auth (email/password, magic link, Google OAuth, GitHub OAuth).
  • Domainlib/domain/: Group, Participant, Expense (amounts in cents), SplitType, SettlementTransaction.

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 (invite-redirect, telemetry)
  • 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 secrets file is lib/core/constants/app_secrets.dart which contains fallback placeholders.

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 SettingsSecrets and variablesActions and add each secret.

Supabase

Secret How to get it
SUPABASE_URL Supabase Dashboard → SettingsAPI → Project URL
SUPABASE_ANON_KEY Supabase Dashboard → SettingsAPIanon public key
SITE_URL Your web app URL, e.g. https://hisab-c8eb1.web.app

Firebase Hosting

Secret How to get it
FIREBASE_SERVICE_ACCOUNT Firebase Console → Project SettingsService accountsGenerate new private key → paste the entire JSON

Android Signing

Generate a keystore (one-time setup):

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

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
KEY_PASSWORD The key password (same as store password if you pressed Enter)

Google Play (optional)

Secret How to get it
PLAY_STORE_SERVICE_ACCOUNT_JSON Google Play Console → SetupAPI 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
keyPassword=your_key_password

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

Packages

No packages published

Contributors 2

  •  
  •