flutter_offline_sync_manager 0.1.2 copy "flutter_offline_sync_manager: ^0.1.2" to clipboard
flutter_offline_sync_manager: ^0.1.2 copied to clipboard

A production-grade Flutter package for managing offline sync operations with crash-safety, restart-safety, and duplication-safety. Works with any backend (REST, Firebase, GraphQL).

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_offline_sync_manager/flutter_offline_sync_manager.dart';
import 'package:hive_flutter/hive_flutter.dart';

/// Minimal example demonstrating offline sync.
///
/// This example shows:
/// - Initializing the sync manager
/// - Enqueueing tasks offline
/// - Manual sync trigger
/// - Basic error handling
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Initialize Hive (required for persistent storage)
  await Hive.initFlutter();
  
  runApp(const SyncExampleApp());
}

class SyncExampleApp extends StatelessWidget {
  const SyncExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Offline Sync Example',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const SyncExampleScreen(),
    );
  }
}

class SyncExampleScreen extends StatefulWidget {
  const SyncExampleScreen({super.key});

  @override
  State<SyncExampleScreen> createState() => _SyncExampleScreenState();
}

class _SyncExampleScreenState extends State<SyncExampleScreen> {
  OfflineSyncManager? _syncManager;
  bool _isInitialized = false;
  String _status = 'Initializing...';

  @override
  void initState() {
    super.initState();
    _initializeSync();
  }

  Future<void> _initializeSync() async {
    try {
      // 1. Initialize store
      final store = HiveSyncStore();
      await store.initialize();

      // 2. Create a mock adapter (for demo purposes)
      // In production, use RestSyncAdapter, FirestoreSyncAdapter, etc.
      final adapter = MockSyncAdapter();

      // 3. Create sync manager
      _syncManager = OfflineSyncManager(
        store: store,
        adapter: adapter,
        config: SyncConfig(
          batchSize: 10,
          maxRetries: 3,
          conflictStrategy: ConflictStrategy.lastWriteWins,
        ),
      );

      setState(() {
        _isInitialized = true;
        _status = 'Ready';
      });
    } catch (e) {
      setState(() {
        _status = 'Error: $e';
      });
    }
  }

  Future<void> _createNote() async {
    if (_syncManager == null) return;

    setState(() => _status = 'Creating note...');

    try {
      // Enqueue a note for sync
      await _syncManager!.enqueue(
        entityType: 'note',
        entityId: 'note-${DateTime.now().millisecondsSinceEpoch}',
        operation: SyncOperation.upsert,
        payload: {
          'title': 'My Note',
          'content': 'This note was created offline and will sync when online.',
          'createdAt': DateTime.now().toIso8601String(),
          'updatedAt': DateTime.now().toIso8601String(),
        },
      );

      setState(() => _status = 'Note enqueued! Tap "Sync Now" to sync.');
    } catch (e) {
      setState(() => _status = 'Error: $e');
    }
  }

  Future<void> _syncNow() async {
    if (_syncManager == null) return;

    setState(() => _status = 'Syncing...');

    try {
      await _syncManager!.sync();
      setState(() => _status = 'Sync completed!');
    } catch (e) {
      setState(() => _status = 'Sync error: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Offline Sync Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Status',
                      style: Theme.of(context).textTheme.titleMedium,
                    ),
                    const SizedBox(height: 8),
                    Text(
                      _status,
                      style: Theme.of(context).textTheme.bodyLarge,
                    ),
                  ],
                ),
              ),
            ),
            const SizedBox(height: 24),
            ElevatedButton.icon(
              onPressed: _isInitialized ? _createNote : null,
              icon: const Icon(Icons.add),
              label: const Text('Create Note (Offline)'),
            ),
            const SizedBox(height: 16),
            ElevatedButton.icon(
              onPressed: _isInitialized ? _syncNow : null,
              icon: const Icon(Icons.sync),
              label: const Text('Sync Now'),
            ),
            const SizedBox(height: 32),
            const Divider(),
            const SizedBox(height: 16),
            Text(
              'How it works:',
              style: Theme.of(context).textTheme.titleMedium,
            ),
            const SizedBox(height: 8),
            const Text(
              '1. Tap "Create Note" to enqueue a task\n'
              '2. The task is stored locally (works offline)\n'
              '3. Tap "Sync Now" to sync to server\n'
              '4. Tasks persist even if app is killed',
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    _syncManager?.dispose();
    super.dispose();
  }
}

/// Mock adapter for demonstration purposes.
///
/// In production, use:
/// - RestSyncAdapter for REST APIs
/// - FirestoreSyncAdapter for Firebase
/// - GraphQLSyncAdapter for GraphQL
/// - Or implement your own SyncAdapter
class MockSyncAdapter implements SyncAdapter {
  @override
  Future<SyncResult> syncBatch(List<SyncTask> tasks) async {
    // Simulate network delay
    await Future.delayed(const Duration(seconds: 1));

    // Mock: All tasks succeed
    final successTaskIds = tasks.map((t) => t.taskId).toList();
    return SyncResult.allSuccess(successTaskIds);
  }
}
4
likes
150
points
58
downloads

Publisher

unverified uploader

Weekly Downloads

A production-grade Flutter package for managing offline sync operations with crash-safety, restart-safety, and duplication-safety. Works with any backend (REST, Firebase, GraphQL).

Repository (GitHub)
View/report issues

Topics

#offline #sync #offline-first #background-sync #conflict-resolution

Documentation

API reference

License

MIT (license)

Dependencies

background_fetch, cloud_firestore, connectivity_plus, flutter, hive, hive_flutter, http, path_provider, workmanager

More

Packages that depend on flutter_offline_sync_manager