See GETTING_STARTED.md for full setup and troubleshooting. For the shortest path:
flutter pub get
dart run build_runner build --delete-conflicting-outputs
flutter run
GETTING_STARTED.md: Detailed onboarding and troubleshootingTASK_COMMANDS.md: Task reference for common workflowsDEVELOPER_GUIDE.md: Development patterns and tipsARCHITECTURE.md: System design and module overviewCONTRIBUTING.md: How to contributeCODE_OF_CONDUCT.md: Community guidelinesSECURITY.md: Vulnerability reportingCHANGELOG.md: Release notes
We welcome contributions! Please read CONTRIBUTING.md and open an issue before large changes.
See LICENSE.
Task is a modern task runner that makes development easier.
# Install Task
brew install go-task/tap/go-task # macOS
# or visit https://taskfile.dev for other platforms
# Setup project
task install
# Run the app
task run
# See all available tasks
task --list๐ See TASK_COMMANDS.md for complete Task reference.
# Install dependencies
flutter pub get
# Run code generation
dart run build_runner build --delete-conflicting-outputs
# Run the app
flutter run๐ See GETTING_STARTED.md for detailed instructions.
Add to ios/Podfile:
platform :ios, '12.0'Add to Info.plist for contacts permission:
<key>NSContactsUsageDescription</key>
<string>We need access to your contacts to add group members</string>Add to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_CONTACTS"/>Min SDK version in android/app/build.gradle:
minSdkVersion 21For each transaction:
If type == expense:
For each payer: balance += amount_paid
For each split: balance -= amount_owed
If type == payment:
For payer: balance -= amount_paid
For recipient: balance += amount_received
1. Calculate net balance for all users
2. Separate into debtors (negative) and creditors (positive)
3. Sort both by magnitude (largest first)
4. While both lists not empty:
a. Match largest debtor with largest creditor
b. Transfer min(|debtor|, creditor)
c. Update balances
d. Remove if settled
Example:
- Initial: A owes 60, B owes 40, C is owed 70, D is owed 30
- Simplified: A pays C (60), B pays C (10), B pays D (30)
- Result: 3 transfers instead of potentially 4+
- Enter your name (device owner/admin)
- Optionally add phone number for WhatsApp
- Tap + button on Groups screen
- Enter group name and description
- Add members from contacts
- Create group
- Open a group
- Tap + (Add Expense) button
- Enter description and amount
- Select who paid (can be multiple people)
- Choose split mode (Equal/Unequal/Percent/Shares)
- Save
- Open a group
- Tap $ (Settle Up) button
- View suggested settlements
- Select payer and recipient
- Enter amount
- Record payment
- Go to Settings โ Backup & Restore
- Export: Tap "Export to Clipboard" โ Save JSON somewhere safe
- Import: Paste JSON โ Tap "Import & Restore"
- Open a group
- Tap share icon
- Select contact
- WhatsApp opens with pre-filled message
Run unit tests:
flutter testRun specific test:
flutter test test/services/debt_calculator_service_test.dart- Offline & Persistent: Data survives app restart
- Backup/Restore: Can export/import full database via JSON
- Settlement Logic: Payments reduce debt without affecting total spend
- WhatsApp Integration: Share summaries via WhatsApp
- Multi-Payer Support: Handle expenses with multiple payers
- Simplified Debts: Greedy algorithm minimizes transfers
- Fast, lightweight NoSQL database
- Built for Flutter
- Easy JSON serialization
- No native dependencies
- Type-safe state management
- Code generation for cleaner syntax
- Better testability
- Automatic dependency injection
- Privacy: Your data never leaves your device
- Offline: Works without internet
- Simple: No authentication, servers, or sync complexity
- Recurring expenses
- Categories and tags
- Charts and analytics
- Multiple currency support
- Receipt photo attachments
- Export to PDF/CSV
- Dark mode
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- Regular Backups: Export your data weekly
- Descriptive Names: Use clear expense descriptions
- Settle Regularly: Record payments as they happen
- Use Simplified View: Easier settlement with fewer transfers
- Lost Data: Import from last backup
- Incorrect Balances: Review transaction history
- WhatsApp Not Opening: Check phone number format
- Contacts Not Loading: Grant contacts permission in settings
For issues, questions, or suggestions:
- Open an issue on GitHub
- Check existing issues for solutions
- Review the documentation
Built with โค๏ธ using Flutter A expense manager which runs in your local only
A local-only, offline-first expense tracking app built with Flutter. Track and split expenses with your groups, similar to Splitwise, but with all data stored locally on your device. No login required, no servers, no internet dependency.
- Admin-Managed Ledger: You are the device owner and admin who records all expenses
- Contacts Integration: Add members from your device contacts
- Multiple Groups: Create and manage multiple expense groups (trips, roommates, etc.)
- Multiple Split Modes:
- Equal: Split evenly among all members
- Unequal: Specify exact amounts for each person
- Percent: Split by percentage
- Shares: Split by ratio (e.g., 1:2:3)
- Multi-Payer Support: Handle expenses where multiple people paid
- Settlement Tracking: Record payments between members
- Net Balances: See who owes whom at a glance
- Simplified Debts: Minimize the number of transactions needed to settle up (greedy algorithm)
- Detailed Insights: View total group spending, individual contributions, and balances
- JSON Export: Export all data to clipboard
- JSON Import: Restore data from backup
- Uninstall-Safe: Export before uninstalling, import after reinstalling
- WhatsApp Integration: Share summaries and reminders via WhatsApp
- Formatted Messages: Auto-generated settlement plans and balance summaries
- Framework: Flutter (Dart)
- State Management: Riverpod (with code generation)
- Local Storage: Hive (NoSQL database)
- Code Generation: json_serializable, riverpod_generator, hive_generator
lib/
โโโ main.dart # App entry point
โโโ app.dart # Main app widget
โโโ features/
โ โโโ groups/
โ โ โโโ models/ # User, Group models
โ โ โโโ providers/ # Riverpod providers for groups/users
โ โ โโโ screens/ # Group UI screens
โ โโโ expenses/
โ โ โโโ models/ # Transaction, SplitMode, TransactionType
โ โ โโโ providers/ # Transaction providers
โ โ โโโ screens/ # Expense & settlement screens
โ โโโ settings/
โ โโโ screens/ # Onboarding, backup/restore
โโโ services/
โ โโโ storage/ # LocalStorageService (Hive)
โ โโโ debt_calculator_service.dart # Net balance & simplify algorithms
โ โโโ contacts_service.dart # Flutter contacts integration
โ โโโ whatsapp_service.dart # WhatsApp share intents
โโโ shared/
โโโ providers/ # Service providers
โโโ theme/ # App theme
โโโ utils/ # Formatters, dialogs
โโโ widgets/ # Reusable widgets
{
id: String, // UUID
name: String,
phoneNumber: String?, // For WhatsApp
isDeviceOwner: bool, // Admin flag
createdAt: DateTime
}{
id: String,
name: String,
description: String?,
memberIds: List<String>, // User IDs
createdBy: String, // User ID
createdAt: DateTime
}{
id: String,
groupId: String,
type: TransactionType, // expense | payment
description: String,
totalAmount: double,
payers: Map<String, double>, // userId -> amount paid
splits: Map<String, double>, // userId -> amount owed
splitMode: SplitMode,
timestamp: DateTime,
notes: String?,
createdBy: String
}Task is a modern task runner that makes development easier.
# Install Task
brew install go-task/tap/go-task # macOS
# or visit https://taskfile.dev for other platforms
# Setup project
task install
# Run the app
task run
# See all available tasks
task --list๐ See TASK_COMMANDS.md for complete Task reference.
# Install dependencies
flutter pub get
# Run code generation
dart run build_runner build --delete-conflicting-outputs
# Run the app
flutter run๐ See GETTING_STARTED.md for detailed instructions.
Add to ios/Podfile:
platform :ios, '12.0'Add to Info.plist for contacts permission:
<key>NSContactsUsageDescription</key>
<string>We need access to your contacts to add group members</string>Add to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_CONTACTS"/>Min SDK version in android/app/build.gradle:
minSdkVersion 21For each transaction:
If type == expense:
For each payer: balance += amount_paid
For each split: balance -= amount_owed
If type == payment:
For payer: balance -= amount_paid
For recipient: balance += amount_received
1. Calculate net balance for all users
2. Separate into debtors (negative) and creditors (positive)
3. Sort both by magnitude (largest first)
4. While both lists not empty:
a. Match largest debtor with largest creditor
b. Transfer min(|debtor|, creditor)
c. Update balances
d. Remove if settled
Example:
- Initial: A owes 60, B owes 40, C is owed 70, D is owed 30
- Simplified: A pays C (60), B pays C (10), B pays D (30)
- Result: 3 transfers instead of potentially 4+
- Enter your name (device owner/admin)
- Optionally add phone number for WhatsApp
- Tap + button on Groups screen
- Enter group name and description
- Add members from contacts
- Create group
- Open a group
- Tap + (Add Expense) button
- Enter description and amount
- Select who paid (can be multiple people)
- Choose split mode (Equal/Unequal/Percent/Shares)
- Save
- Open a group
- Tap $ (Settle Up) button
- View suggested settlements
- Select payer and recipient
- Enter amount
- Record payment
- Go to Settings โ Backup & Restore
- Export: Tap "Export to Clipboard" โ Save JSON somewhere safe
- Import: Paste JSON โ Tap "Import & Restore"
- Open a group
- Tap share icon
- Select contact
- WhatsApp opens with pre-filled message
Run unit tests:
flutter testRun specific test:
flutter test test/services/debt_calculator_service_test.dart- Offline & Persistent: Data survives app restart
- Backup/Restore: Can export/import full database via JSON
- Settlement Logic: Payments reduce debt without affecting total spend
- WhatsApp Integration: Share summaries via WhatsApp
- Multi-Payer Support: Handle expenses with multiple payers
- Simplified Debts: Greedy algorithm minimizes transfers
- Fast, lightweight NoSQL database
- Built for Flutter
- Easy JSON serialization
- No native dependencies
- Type-safe state management
- Code generation for cleaner syntax
- Better testability
- Automatic dependency injection
- Privacy: Your data never leaves your device
- Offline: Works without internet
- Simple: No authentication, servers, or sync complexity
- Recurring expenses
- Categories and tags
- Charts and analytics
- Multiple currency support
- Receipt photo attachments
- Export to PDF/CSV
- Dark mode
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- Regular Backups: Export your data weekly
- Descriptive Names: Use clear expense descriptions
- Settle Regularly: Record payments as they happen
- Use Simplified View: Easier settlement with fewer transfers
- Lost Data: Import from last backup
- Incorrect Balances: Review transaction history
- WhatsApp Not Opening: Check phone number format
- Contacts Not Loading: Grant contacts permission in settings
For issues, questions, or suggestions:
- Open an issue on GitHub
- Check existing issues for solutions
- Review the documentation
Built with โค๏ธ using Flutter A expense manager which runs in your local only