Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

SyncVault Example — Offline-First Todo App

A fully-functional Todo application demonstrating the power of SyncVault for offline-first data synchronization.

✨ Features Demonstrated

Feature Description
🔄 Automatic Queueing Requests made while offline are automatically queued
☁️ Auto-Sync Queued requests sync automatically when connectivity returns
🎯 Idempotency Keys Prevents duplicate operations during retries
📊 Status Stream Real-time sync status updates for UI feedback
Optimistic UI Immediate UI updates with pending sync indicators
🔢 Pending Count Track how many requests are waiting to sync

🚀 Getting Started

Prerequisites

  • Flutter SDK (3.10+)
  • A device or emulator

Run the App

cd example
flutter pub get
flutter run

📱 App Walkthrough

Main Screen

The app features a beautiful dark theme with:

  • Header — App title with animated sync button
  • Status Bar — Online/offline indicator + pending count badge
  • Input Field — Add new todos
  • Todo List — Swipe-to-delete with completion toggle

Visual Indicators

Indicator Meaning
🟢 Green dot Device is online
🟡 Amber dot Device is offline
☁️ Cloud icon on todo Item pending sync
⏳ "X pending" badge Number of queued requests
✓ "Synced" badge All requests synchronized

Sync Status Colors

Color Status
🟢 Green SyncStatus.synced — All caught up
🟣 Purple SyncStatus.syncing — Currently processing queue
🟡 Amber SyncStatus.pending — Items waiting to sync
🔴 Red SyncStatus.error — Sync error occurred

🏗️ Code Structure

example/
├── lib/
│   ├── main.dart           # Main app with SyncVault integration
│   ├── todo_model.dart     # Todo data model
│   └── sqflite_example.dart # Alternative: SQLite storage example
└── pubspec.yaml

💡 Key Integration Points

1. Initialization

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  final dir = await getApplicationDocumentsDirectory();

  await SyncVault.init(
    config: SyncVaultConfig(
      baseUrl: 'https://jsonplaceholder.typicode.com',
      storagePath: dir.path,
      maxRetries: 3,
    ),
  );

  runApp(const SyncVaultExampleApp());
}

2. Making Offline-Safe Requests

// POST — Create todo
final response = await SyncVault.instance.post(
  '/todos',
  data: todo.toJson(),
  idempotencyKey: 'create_todo_${todo.id}',
);

// Track the action ID for event listening
if (response.actionId != null) {
  _todoToActionId[todo.id] = response.actionId!;
}

if (response.isQueued) {
  // Show offline indicator
} else if (response.isSent) {
  // Update UI with success
}

3. Listening to Sync Events (Event Bus)

// Wrap your screen with SyncVaultListener
SyncVaultListener(
  onSuccess: (event) {
    // Called when any action completes successfully
    _markTodoSynced(event.id);
    showSnackBar('Synced!');
  },
  onDeadLetter: (event) {
    // Called when an action permanently fails
    showSnackBar('Failed: ${event.error}');
  },
  child: YourScreen(),
)

4. Reactive Status with SyncStatusBuilder

// Automatically rebuilds when sync status changes
SyncStatusBuilder(
  builder: (context, status) {
    return Icon(
      status == SyncStatus.syncing ? Icons.sync : Icons.cloud_done,
      color: _getSyncColor(status),
    );
  },
)

5. Per-Item Sync Indicators with SyncEventBuilder

// Show sync progress for a specific action
SyncEventBuilder(
  actionId: actionId,
  builder: (context, lastEvent) {
    if (lastEvent?.status == SyncEventStatus.started) {
      return CircularProgressIndicator();
    }
    return Icon(Icons.cloud_upload);
  },
)

6. Checking Pending Count

final pendingCount = await SyncVault.instance.pendingCount;

7. Manual Sync Trigger

final syncedCount = await SyncVault.instance.processQueue();

🧪 Testing Offline Behavior

On Emulator

  1. Open the app
  2. Add a few todos
  3. Enable Airplane Mode in the emulator
  4. Add more todos — notice the "pending" badge
  5. Disable Airplane Mode
  6. Watch the automatic sync happen!

On Physical Device

  1. Turn off WiFi and mobile data
  2. Use the app normally
  3. Re-enable connectivity
  4. Observe auto-sync

📂 Alternative: SQLite Storage

See sqflite_example.dart for using SQLite instead of Hive:

final sqliteAdapter = SqfliteStorageAdapter();

await SyncVault.init(
  config: SyncVaultConfig(
    baseUrl: 'https://api.example.com',
    storage: sqliteAdapter,
  ),
);

🎨 Design Details

  • Color Palette: Indigo/Purple gradients with emerald/amber accents
  • Typography: SF Pro Display (system font)
  • Theme: Material 3 Dark
  • Animations: Pulse effect on sync button, smooth transitions

📝 API Used

This example uses JSONPlaceholder as a demo API:

  • POST /todos — Create todo
  • PATCH /todos/:id — Update todo
  • DELETE /todos/:id — Delete todo

Note: JSONPlaceholder is a fake API that returns success responses but doesn't persist data. Perfect for demonstrating SyncVault's behavior!

🔗 Related


Built with 💜 to demonstrate offline-first architecture in Flutter.