qubeena07/TogglSub

A privacy-first, automated subscription tracker for iOS and Android that intelligently monitors your emails to prevent unwanted renewal charges.

★ 0Forks 0DartGitHub ↗Compare

README

TogglSub

A Flutter subscription tracker that automatically detects subscriptions from your Gmail inbox, tracks spending, sends renewal reminders, and helps you manage all your recurring payments in one place.

Features

  • Gmail Auto-Scan — Scans your inbox using the Gmail API + Gemini AI (Cloud Function) to extract subscription details (provider, cost, renewal date, billing cycle)
  • Manual Entry — Add subscriptions manually with full control over all fields
  • Renewal Notifications — Local push notifications at 7 days, 1 day, and same-day before renewal
  • Email Reminders — Scheduled Cloud Function sends daily email digests for upcoming renewals
  • Price Hike Detection — Tracks price history and alerts you when a subscription's cost increases
  • Cost Splitting — Split subscription costs with friends and track your personal share
  • Analytics Dashboard — Spending breakdown by category, top subscriptions, monthly/yearly projections
  • Privacy Mode — Toggle to hide all cost amounts in the UI
  • One-Click Cancel — Direct links to 35+ popular subscription management pages (Netflix, Spotify, etc.)
  • Offline-First — Isar local database with background Firestore sync
  • Multi-Auth — Google Sign-In, Apple Sign-In, and Email/Password with email verification
  • Account Linking — Link multiple auth providers to a single account

Screenshots

Architecture

lib/
├── main.dart                          # Entry point, Firebase/Isar/Notification init, auth gate
├── env_config.dart                    # Environment variables via --dart-define-from-file
├── firebase_options.dart              # Firebase platform config (reads from env_config)
│
├── models/
│   ├── subscription.dart              # Core Subscription model, Firestore serialization
│   ├── subscription_isar.dart         # Isar collection schema
│   └── subscription_isar.g.dart       # Generated Isar adapter
│
├── providers/
│   └── providers.dart                 # All Riverpod providers, SubscriptionRepository,
│                                      # auto Gmail sync, analytics providers
│
├── services/
│   ├── auth_service.dart              # Google/Apple/Email auth, account linking
│   ├── gmail_service.dart             # Gmail API integration, email parsing, Cloud Function calls
│   ├── isar_service.dart              # Local Isar DB operations (offline-first)
│   └── notification_service.dart      # Local notification scheduling & permissions
│
├── screens/
│   ├── auth/
│   │   ├── login_screen.dart          # Sign-in screen (Google, Apple, Email)
│   │   ├── verify_email_screen.dart   # Email verification flow
│   │   └── link_account_dialog.dart   # Link auth providers dialog
│   ├── dashboard/
│   │   ├── dashboard_screen.dart      # Main subscription list with filters
│   │   ├── add_subscription_sheet.dart # Manual subscription entry
│   │   └── gmail_import_sheet.dart    # Gmail scan results & selective import
│   ├── analytics/
│   │   └── analytics_screen.dart      # Spending analytics & charts
│   └── profile/
│       └── profile_screen.dart        # User settings, email reminders toggle, test notifications
│
└── widgets/
    └── private_cost_text.dart         # Privacy-aware cost display widget

functions/
└── src/
    └── index.ts                       # Cloud Functions:
                                       #   - analyzeSubscriptionEmails (Gemini AI parsing)
                                       #   - sendEmailReminders (daily scheduled emails)

Data Flow

Gmail Inbox
    │
    ▼
Gmail API (googleapis) ──► Cloud Function (Gemini 2.5 Flash)
    │                           │
    │                           ▼
    │                    Structured JSON
    │                    (provider, cost, date)
    │                           │
    ▼                           ▼
GmailService ──────────► ExtractedSubscriptionData
                                │
                                ▼
                    SubscriptionRepository
                         │           │
                         ▼           ▼
                      Isar DB    Firestore
                    (primary)    (sync/backup)
                         │
                         ▼
                   Riverpod Stream
                         │
                         ▼
                    Dashboard UI

State Management

  • Riverpod for all app state
  • subscriptionsStreamProvider — Isar stream for instant offline-first UI
  • autoGmailSyncProvider — Background sync with 30-minute cooldown
  • filteredSubscriptionsProvider — Dashboard filters (All / Active / Renewing Soon)
  • Analytics providers for spending breakdowns and projections

Storage

Layer Technology Purpose
Local Isar 3.x Primary data source, instant reads, offline support
Cloud Firestore Cross-device sync, backup, email reminder queries
Secure flutter_secure_storage OAuth tokens (Keychain/Keystore)

Tech Stack

Category Package
Framework Flutter 3.x (Dart >=3.4)
State flutter_riverpod
Auth firebase_auth, google_sign_in, sign_in_with_apple
Database isar (local), cloud_firestore (cloud)
API googleapis (Gmail), cloud_functions
AI Gemini 2.5 Flash (via @google/generative-ai in Cloud Functions)
Notifications flutter_local_notifications, timezone
UI google_fonts, flutter_animate, shimmer, cached_network_image
Utilities intl, url_launcher, crypto, uuid, permission_handler

Getting Started

Prerequisites

  • Flutter SDK >=3.4.0
  • Firebase project with Auth, Firestore, and Cloud Functions enabled
  • Google Cloud project with Gmail API enabled
  • Node.js 18+ (for Cloud Functions)

Setup

  1. Clone the repository

    git clone https://github.com/yourusername/TogglSub.git
    cd TogglSub
  2. Create your .env file from the template

    cp .env.example .env
    # Fill in your Firebase API keys
  3. Firebase configuration files (not in repo — get from Firebase Console)

    • android/app/google-services.json
    • ios/Runner/GoogleService-Info.plist
    • macos/Runner/GoogleService-Info.plist
  4. Install dependencies

    flutter pub get
  5. Generate Isar schemas

    dart run build_runner build --delete-conflicting-outputs
  6. Deploy Cloud Functions

    cd functions
    npm install
    # Set the Gemini API key as a Firebase secret
    firebase functions:secrets:set GEMINI_API_KEY
    firebase deploy --only functions
  7. Run the app

    flutter run --dart-define-from-file=.env

Build

# iOS
flutter build ios --dart-define-from-file=.env

# Android
flutter build apk --dart-define-from-file=.env

Testing on Android

After building the APK, you can test it on an Android device or emulator.

Prerequisites

  • Android device with USB debugging enabled, or Android emulator
  • ADB (Android Debug Bridge) installed

Steps

  1. Build the APK (if not already done):

    flutter build apk --dart-define-from-file=.env
  2. Locate the APK: The release APK is generated at apk/app-release.apk

  3. Install on device:

    • Connect your Android device via USB
    • Enable USB debugging in Developer Options
    • Run:
      adb devices  # Verify device is connected
      adb install build/app/outputs/flutter-apk/app-release.apk
  4. Install on emulator:

    • Start an Android emulator
    • Run:
      adb install build/app/outputs/flutter-apk/app-release.apk
  5. Launch the app:

    • Open the app on your device/emulator
    • Test features like authentication, subscription management, and notifications

Notes

  • Ensure Firebase and Gmail API are properly configured for full functionality
  • For production testing, use a real device with Google Play Services
  • The APK is signed with the debug keystore by default; for release distribution, configure signing in android/app/build.gradle.kts

Firebase Setup

  1. Authentication — Enable Google, Apple, and Email/Password providers
  2. Firestore — Create database with the security rules in firestore.rules
  3. Cloud Functions — Deploy functions from the functions/ directory
  4. Gmail API — Enable in Google Cloud Console and configure OAuth consent screen
  5. Trigger Email Extension (optional) — Install for email reminder delivery

OAuth Consent Screen

To allow all users (not just test users) to sign in:

  1. Go to Google Cloud Console > APIs & Services > OAuth consent screen
  2. Click Publish App to move from Testing to Production
  3. If using gmail.readonly scope, submit for Google verification review

Firestore Security Rules

User-scoped access — each user can only read/write their own subscriptions:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId}/{document=**} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
  }
}

Cloud Functions

Function Trigger Description
analyzeSubscriptionEmails HTTPS Callable Sends email content to Gemini 2.5 Flash for structured extraction
sendEmailReminders Pub/Sub (daily 9:00 UTC) Queries Firestore for upcoming renewals, queues reminder emails

License

This project is proprietary. All rights reserved.

Contributors

qubeena07

Issues