Skip to content

benjaminudoh10/balance-sheet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

105 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Balanced

Balanced is a Flutter mobile app for recording income and expenses, seeing your running balance, and reviewing transactions over time. The project package name is balance_sheet; the in-app product name is Balanced, with the tagline “…know where your money goes.”


What the app does

  • Home (main tab) — Shows total balance, today’s net (income minus expense for the current day), and a Recent transactions list. Add entries via Income and Expense actions; open All transactions for the full report view.
  • Contacts — Manage people or entities you attach to transactions (optional linkage from the transaction form).
  • Profile — Theme (light / dark / system), font family, app lock (PIN and optional biometrics), and backup export/import.
  • Insights — Period summary (today vs yesterday, this week, this month, last month): total expenses vs the comparison window, category donut + horizontal category bars, weekly income vs expense grouped bars, daily net line chart, and short takeaways. Activity remains a placeholder; the shell and bottom navigation are in place.

Money is stored and calculated in minor units (integer cents/kobo-style amounts). Display formatting in lib/utils.dart uses Nigerian Naira (NGN) via intl; adjust there if you target another currency.


Tech stack

Area Choice
Framework Flutter (Dart SDK >=3.0.0 <4.0.0)
State & navigation GetX (GetMaterialApp, Obx, controllers, Get.to / Get.offAll)
Local database sqflite — SQLite file on device
Key-value preferences get_storage — PIN metadata, theme, font, fingerprint flag
UI Material 3 (useMaterial3: true), google_fonts, modal_bottom_sheet, pinput, flutter_slidable, fl_chart (Insights)
Security crypto (salted PIN hash), local_auth
Backup JSON file via file_picker

Project structure

High-level layout of lib/:

lib/
├── main.dart                 # App entry: GetStorage init, global GetX controllers, GetMaterialApp + themes
├── enums.dart                # TransactionType, ReportType
├── utils.dart                # Currency / signed net formatting
├── file_handler.dart         # Legacy / commented CSV helpers (not active)
│
├── constants/                # App-wide constants
│   ├── app.dart              # Storage keys (PIN, theme, font)
│   ├── db.dart               # DB name, table names, schema version
│   ├── category.dart         # Category keys, labels, icons, pill colors (keys are stable across releases)
│   ├── colors.dart           # Legacy snackbar / accent colors
│   └── backup_constants.dart # Backup JSON format id + version
│
├── theme/
│   ├── app_theme.dart        # Light/dark ThemeData, Google Font wiring, scaled text theme (“midnight” scale)
│   └── app_palette.dart      # AppPalette ThemeExtension — semantic colors for light/dark
│
├── controllers/              # GetX controllers (business + UI state)
│   ├── appController.dart    # Tab index, splash → lock vs home, theme mode & font persistence
│   ├── transactionController.dart
│   ├── contactController.dart
│   ├── reportController.dart # Period filters, report list state (scoped to report screen lifecycle)
│   ├── insights_controller.dart # Insights tab aggregates and period bounds
│   └── securityController.dart
│
├── models/
│   ├── transaction.dart
│   └── contact.dart
│
├── database/
│   ├── db.dart               # Singleton AppDb, openDatabase, onCreate / onUpgrade migrations
│   └── operations.dart       # CRUD and queries used by controllers
│
├── security/
│   └── pin_hash.dart         # Salted SHA-256 PIN; no plaintext PIN on disk
│
├── backup/
│   └── backup_service.dart   # JSON export/import of DB rows + GetStorage preferences
│
├── dialogs/                  # Modals for transaction actions, contacts
├── widgets/                  # Reusable UI (inputs, nav, pin, category pills, transaction rows, grid painter)
├── screens/                  # Full-screen routes (splash, home shell, tabs, lock, forms, report)
└── assets/                   # Images (e.g. launcher / splash source)

Platform folders (android/, ios/) contain standard Flutter embedding; launcher icon and native splash are configured in pubspec.yaml (flutter_launcher_icons, flutter_native_splash).


Architecture and decisions

GetX as the app backbone

  • Controllers are registered once in lib/main.dart: TransactionController, SecurityController, AppController, ContactController.
  • Reactive UI uses Obx / .obs where lists or settings must update without manual setState in parent widgets.
  • Default transition is Transition.downToUp (GetX config) for a consistent sheet-like feel on pushes.
  • ReportController is created with Get.put inside ReportView and deleted in dispose so report-specific state does not leak globally.

Single source of truth for data

  • Transactions and contacts live in SQLite (lib/database/db.dart). Schema version and migrations are in onUpgrade (e.g. version 3 reworked the transactions table and removed legacy tables).
  • Preferences and secrets metadata (not the raw PIN) live in GetStorage: theme mode, font id, fingerprint toggle, PIN hash + salt.

Navigation model

  1. Splash is the initial home route (branding + short delay).
  2. AppController.onReady routes to LockScreen if a PIN is configured, otherwise Home.
  3. Home is a 5-tab scaffold: Main, Contacts, Activity (placeholder), Insights, Profile. PopScope sends Android back to tab 0 when not on the first tab.

Forms and sheets


Data model

Transaction (transactions table)

  • Fields include: description, type (income / expenditure), amount (integer minor units), date (epoch ms), category (string key), optional contactId.
  • The Dart model is Transaction; JSON serialization matches backup and DB rows.

Categories

  • Defined in lib/constants/category.dart. Keys are treated as stable API once shipped (labels and styling may change). Icons and per-theme pill colors (CategoryPillStyle) keep lists scannable in both light and dark mode.

Contacts

  • Simple id + name table; transactions reference contactId where relevant.

UI and design system

“Midnight Mint” palette

  • Semantic colors live in AppPalette (lib/theme/app_palette.dart), registered as a ThemeExtension on ThemeData. Screens resolve colors with AppPalette.of(context) so widgets stay theme-aware.
  • Dark default is a deep blue-gray background with mint (positive / income) and coral (expense / loss) accents. Light mode keeps the same role structure with adjusted contrast.

Typography

  • app_theme.dart applies Google Fonts with a fixed type scale (midnightScaledTextTheme) so switching font family does not break hierarchy.
  • Users can pick among several sans and monospace families (AppFontIds); the choice is persisted and applied when building ThemeData.

Recurring visual motifs

  • MidnightGridPainter — Subtle grid lines behind scrollable content for depth without clutter.
  • Glass-style balance card — Backdrop blur, gradient, and accent tied to whether today’s net is positive or negative (MainView).
  • Bottom navigation — Custom MidnightBottomNav aligned with the same visual language.
  • Transaction rows — Built in widgets.dart with flutter_slidable: swipe for edit/delete, category pills from Categories, and consistent typography.

Internal UX notes for the transaction list live under design/ (e.g. redesign markdown); treat them as product/design references, not runtime code.


Security

  • PIN — Four digits (AppConstants.PIN_CODE_LENGTH). Stored as salt + SHA-256 hash (PinHash); plaintext PIN keys are cleared on upgrade path when setting a new PIN.
  • Biometrics — Optional; local_auth integrates with SecurityController for unlock when enabled.
  • Lock flowsLockScreen for unlock / PIN removal confirmation; PinLock for setup and change flows.

Backup and restore

  • BackupService exports a JSON document with:
    • Format id / version (BackupConstants)
    • DB schema version
    • Contacts and transactions
    • Selected GetStorage keys (theme, font, fingerprint, PIN hash/salt — so restores preserve lock state if desired)
  • Import replaces local DB content and preferences; controllers expose refresh paths after import (see backup service and syncFromStorage-style methods on AppController / SecurityController).

Development

Prerequisites

  • Flutter SDK compatible with the environment constraint in pubspec.yaml.
  • Xcode (iOS) and/or Android Studio / SDK (Android) as usual for Flutter mobile builds.

Run

cd balance_sheet
flutter pub get
flutter run

Tests

flutter test

Version and branding assets

  • App version: pubspec.yamlversion: (e.g. 1.3.0+1).
  • ProfileView shows a _kAppVersion constant — keep it in sync with pubspec.yaml when releasing.
  • Regenerate launcher icon / splash after asset changes:
dart run flutter_launcher_icons
dart run flutter_native_splash:create

Contributing notes

  • Prefer small, focused changes; match existing naming, GetX patterns, and AppPalette usage rather than introducing parallel styling systems.
  • Do not rename category keys in category.dart for existing categories without a migration strategy — comments in that file call this out explicitly.
  • When changing the backup JSON shape, bump BackupConstants.formatVersion and document the migration expectation for older files.

License / publishing

The package is marked publish_to: 'none' in pubspec.yaml (private app). Adjust if you later open-source or publish tooling around it.

About

A flutter app to record expenses and track how income is spent

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors