Flutter Offline Queue Pro πŸš€

A production-grade, offline-first networking layer for Flutter. Capture API calls when connectivity is lost and automatically execute them when the internet returns.

Similar to how Uber, WhatsApp, and Instagram handle actions, flutter_offline_queue_pro ensures that user actions like likes, comments, bookings, and payments are never lost due to flaky network conditions.

Idle State Action Captured Queue Count

✨ Features

  • πŸ“Ά Smart Connectivity Detection: Uses connectivity_plus combined with real internet reachability checks.
  • πŸ“¦ Pluggable Storage:
    • Isar (Default - High performance)
    • Hive (Lightweight backup)
    • Custom Storage Adapter support.
  • πŸ”„ Advanced Retry System:
    • Exponential backoff.
    • Configurable retry limits and intervals.
  • ⚑ Queue Management:
    • Priority-based execution (High, Normal, Low).
    • Request fingerprinting to prevent duplicates (Debouncing).
    • Manual triggers, cancel specific requests, and clear queue.
  • πŸ” Authentication Handling: Automatically pauses the queue on 401 errors, allowing token refresh before resuming.
  • πŸ“Ž Full HTTP Support: GET, POST, PUT, PATCH, DELETE + Multipart/form-data support.
  • πŸ“Š Real-time Progress: Stream based progress tracking and queue status updates.

πŸš€ Quick Start

1. Initialize the Queue

Initialize the queue in your main() or at the start of your app.

await OfflineQueue.init(
  baseUrl: "https://api.example.com",
  retryLimit: 5,
  retryInterval: Duration(seconds: 5),
  debug: true, // Enable logging
);

2. Capture Actions

Replace your standard HTTP calls with OfflineQueue methods.

// Simple POST request
await OfflineQueue.post(
  "/like", 
  body: {"post_id": 12},
  priority: OfflinePriority.high,
);

// Request with headers (Auth tokens are handled automatically via provider)
await OfflineQueue.get("/profile");

πŸ›  Advanced Usage

Custom Auth Handling

Supply an authHeaderProvider and onTokenExpired callback during initialization.

await OfflineQueue.init(
  baseUrl: "https://api.example.com",
  authHeaderProvider: () async => {
    'Authorization': 'Bearer ${await getSavedToken()}',
  },
  onTokenExpired: () async {
    final success = await refreshToken();
    return success; // If true, the queue resumes and retries the failed request
  },
);

Pluggable Storage

By default, Isar is used. You can switch to Hive or your own:

await OfflineQueue.init(
  baseUrl: "...",
  storage: HiveStorage(), // Use Hive instead of Isar
);

Monitoring the Queue

// Get number of pending requests
int count = await OfflineQueue.pendingCount;

// Listen to sync progress
OfflineQueue.progressStream.listen((progress) {
  print("Syncing: ${(progress * 100).toStringAsFixed(0)}%");
});

// Listen to status changes
OfflineQueue.statusStream.listen((status) {
  print("Queue is ${status.name}");
});

πŸ“Š Comparison vs Normal HTTP/Dio

Feature Standard (http/dio) Offline Queue Pro
Offline Handling Throws Exception / Fails Automatically Queues
Retry Logic Manual Implementation Automatic Exponential Backoff
Persistence Lost on App Close Persisted in Local DB
Duplicates Risk of double execution Fingerprinting / Debouncing
UX Shows "No Connection" error Seamless "Action Captured" experience

🧩 Edge Case Handling

  1. Duplicate Prevention: Every request generates a unique fingerprint (SHA-256) based on method, URL, and body. If a request is already in the queue, identical subsequent requests are ignored (debouncing).
  2. App Restarts: Since requests are stored in Isar/Hive, they persist even if the app or device restarts. The queue initializes and checks for pending tasks on startup.
  3. Partial Success: If a sync session is interrupted (e.g., network drops again), successfully completed requests are removed, while failed ones stay in the queue with an incremented retry counter.
  4. 401 Unauthorized: The queue intelligently pauses when it encounters an auth error. This prevents "hammering" the server with unauthorized requests while your app refreshes the token.
  5. Multipart/Large Files: Supports file path storage for large uploads. Instead of storing the whole file in the DB, it stores the path and reads it during execution.

πŸ“‚ Folder Structure

lib/
 β”œβ”€β”€ flutter_offline_queue_pro.dart (Main Facade)
 └── src/
      β”œβ”€β”€ core/
      β”‚    β”œβ”€β”€ queue_manager.dart (Orchestrator)
      β”‚    β”œβ”€β”€ queue_worker.dart  (Execution logic)
      β”œβ”€β”€ storage/
      β”‚    β”œβ”€β”€ queue_storage.dart (Interface)
      β”‚    β”œβ”€β”€ isar_storage.dart  (Isar Implementation)
      β”‚    └── hive_storage.dart  (Hive Implementation)
      β”œβ”€β”€ models/
      β”‚    β”œβ”€β”€ offline_request.dart
      β”‚    β”œβ”€β”€ priority.dart
      β”‚    └── retry_policy.dart
      β”œβ”€β”€ services/
      β”‚    └── connectivity_service.dart
      └── utils/
           β”œβ”€β”€ fingerprinter.dart
           └── logger.dart

πŸ“ License

This project is licensed under the MIT License - see the LICENSE file for details.