betuko_offline_sync 3.1.0 copy "betuko_offline_sync: ^3.1.0" to clipboard
betuko_offline_sync: ^3.1.0 copied to clipboard

Ultra-simple offline-first Flutter package. Just get(), save(), and syncAll(). Automatic local storage with Hive, manual sync when you want.

Betuko Offline Sync #

pub package likes popularity

Ultra-simple offline-first package for Flutter. Your app always works, online or offline.

✨ Features #

  • 🚀 Super Simple API - Just get(), save(), syncAll()
  • 📱 Always Fast - get() always returns local data instantly
  • 🔄 Manual Sync - User decides when to sync with syncAll()
  • Auto Sync - Automatically syncs every 10 minutes when online
  • 🔌 Reconnection Sync - Automatically syncs when internet connection is restored
  • 💾 Auto Storage - Uses Hive for persistent local storage
  • 📊 Sync Status - Know exactly what's synced and what's pending
  • 🔧 Debug Tools - Built-in debugging and reset utilities

📦 Installation #

dependencies:
  betuko_offline_sync: ^3.1.0
flutter pub get

🚀 Quick Start #

1. Configure (once at app start) #

import 'package:betuko_offline_sync/betuko_offline_sync.dart';

void main() {
  GlobalConfig.init(
    baseUrl: 'https://your-api.com',
    token: 'your-auth-token',
  );
  runApp(MyApp());
}

2. Create a Manager #

final reports = OnlineOfflineManager(
  boxName: 'reports',
  endpoint: '/api/reports',
);

3. Use It! #

// Get data (ALWAYS returns local data - instant!)
final data = await reports.get();

// Save data (stored locally, synced later)
await reports.save({
  'title': 'My Report',
  'date': DateTime.now().toIso8601String(),
});

// Sync with server (when user wants fresh data)
await OnlineOfflineManager.syncAll();

⚡ Automatic Synchronization #

The library automatically syncs your data in two scenarios:

1. Periodic Sync (Every 10 minutes) #

When your app is online, syncAll() is automatically called every 10 minutes to keep your data fresh.

2. Reconnection Sync #

When the app detects that internet connection is restored (from offline to online), it automatically triggers syncAll() to sync any pending data.

No configuration needed! This works automatically once you create your first OnlineOfflineManager.

// Just create managers - auto-sync starts automatically!
final reports = OnlineOfflineManager(
  boxName: 'reports',
  endpoint: '/api/reports',
);

// Auto-sync will:
// - Run every 10 minutes when online
// - Run immediately when connection is restored

You can still call syncAll() manually anytime you want to force a sync.

📖 API Reference #

Instance Methods #

Method Returns Description
get() List<Map> All local data
getSynced() List<Map> Only synced data
getPending() List<Map> Only pending data
getFullData() FullSyncData All data + counts
getSyncInfo() SyncInfo Just counts
save(Map data) void Save locally
delete(String id) void Delete by ID
clear() void Clear all data
reset() void Clear data + cache
dispose() void Release resources

Static Methods #

Method Returns Description
syncAll() Map<String, SyncResult> Sync all managers
getAllSyncInfo() Map<String, SyncInfo> Status of all managers
resetAll() void Reset everything
debugInfo() void Print debug info
getAllBoxesInfo() List<HiveBoxInfo> Hive boxes info
getTotalRecordCount() int Total records
getTotalPendingCount() int Total pending
deleteAllBoxes() void Delete from disk

📊 Check Sync Status #

Per Manager #

// Get full data with status
final data = await reports.getFullData();

print('Total: ${data.total}');
print('Synced: ${data.syncedCount}');
print('Pending: ${data.pendingCount}');
print('Percentage: ${data.syncPercentage}%');

// Access the actual data
for (final item in data.synced) {
  print('Synced: ${item['title']}');
}

for (final item in data.pending) {
  print('Pending: ${item['title']}');
}

All Managers #

final allStatus = await OnlineOfflineManager.getAllSyncInfo();

for (final entry in allStatus.entries) {
  print('${entry.key}: ${entry.value.synced}/${entry.value.total}');
}

🔧 Debug Tools #

// Print complete debug info
await OnlineOfflineManager.debugInfo();

// Output:
// ═══════════════════════════════════════════════════════════
// 📊 DEBUG INFO - OnlineOfflineManager
// ═══════════════════════════════════════════════════════════
// 📦 Managers activos: 2
//    • reports: 150 registros (3 pendientes)
//    • users: 50 registros (0 pendientes)
// 💾 Boxes Hive:
//    • reports: 150 registros (abierta)
//    • users: 50 registros (abierta)
// ⚙️ GlobalConfig:
//    • Inicializado: true
//    • BaseURL: https://api.com
// ═══════════════════════════════════════════════════════════

🔄 Multiple Managers #

// Create multiple managers
final reports = OnlineOfflineManager(
  boxName: 'reports',
  endpoint: '/api/reports',
);

final users = OnlineOfflineManager(
  boxName: 'users',
  endpoint: '/api/users',
);

final products = OnlineOfflineManager(
  boxName: 'products',
  endpoint: '/api/products',
);

// Sync ALL with one call
final results = await OnlineOfflineManager.syncAll();

for (final entry in results.entries) {
  if (entry.value.success) {
    print('✅ ${entry.key}: synced');
  } else {
    print('❌ ${entry.key}: ${entry.value.error}');
  }
}

🎯 Complete Example #

import 'package:flutter/material.dart';
import 'package:betuko_offline_sync/betuko_offline_sync.dart';

void main() {
  GlobalConfig.init(
    baseUrl: 'https://api.example.com',
    token: 'your-token',
  );
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final reports = OnlineOfflineManager(
    boxName: 'reports',
    endpoint: '/api/reports',
  );
  
  List<Map<String, dynamic>> data = [];
  bool isSyncing = false;

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

  Future<void> _loadData() async {
    final result = await reports.get();
    setState(() => data = result);
  }

  Future<void> _sync() async {
    setState(() => isSyncing = true);
    await OnlineOfflineManager.syncAll();
    await _loadData();
    setState(() => isSyncing = false);
  }

  Future<void> _addReport() async {
    await reports.save({
      'title': 'Report ${DateTime.now().millisecondsSinceEpoch}',
      'date': DateTime.now().toIso8601String(),
    });
    await _loadData();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Offline-First App'),
          actions: [
            IconButton(
              icon: isSyncing 
                ? SizedBox(
                    width: 20, 
                    height: 20, 
                    child: CircularProgressIndicator(color: Colors.white))
                : Icon(Icons.sync),
              onPressed: isSyncing ? null : _sync,
            ),
          ],
        ),
        body: ListView.builder(
          itemCount: data.length,
          itemBuilder: (context, index) {
            final item = data[index];
            final isSynced = item['sync'] == 'true';
            
            return ListTile(
              title: Text(item['title'] ?? 'No title'),
              trailing: Icon(
                isSynced ? Icons.cloud_done : Icons.cloud_off,
                color: isSynced ? Colors.green : Colors.orange,
              ),
            );
          },
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: _addReport,
          child: Icon(Icons.add),
        ),
      ),
    );
  }

  @override
  void dispose() {
    reports.dispose();
    super.dispose();
  }
}

🔐 Update Token #

// After login or token refresh
GlobalConfig.updateToken('new-token');

🗑️ Reset Everything #

// Reset all data (useful for logout)
await OnlineOfflineManager.resetAll();

// Or delete all boxes from disk
await OnlineOfflineManager.deleteAllBoxes();

📋 Data Classes #

SyncInfo #

class SyncInfo {
  int total;           // Total records
  int synced;          // Synced records
  int pending;         // Pending records
  double syncPercentage;  // 0-100
  bool isFullySynced;     // true if pending == 0
}

FullSyncData #

class FullSyncData {
  List<Map> all;      // All data
  List<Map> synced;   // Synced data
  List<Map> pending;  // Pending data
  int total;
  int syncedCount;
  int pendingCount;
  double syncPercentage;
  bool isFullySynced;
}

SyncResult #

class SyncResult {
  bool success;
  String? error;
}

🤝 Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License #

MIT License - see LICENSE for details.

👨‍💻 Author #

Betuko - GitHub

2
likes
0
points
65
downloads

Publisher

unverified uploader

Weekly Downloads

Ultra-simple offline-first Flutter package. Just get(), save(), and syncAll(). Automatic local storage with Hive, manual sync when you want.

Repository (GitHub)
View/report issues

Topics

#offline-first #sync #hive #local-storage #cache

Documentation

Documentation

License

unknown (license)

Dependencies

connectivity_plus, flutter, hive, hive_flutter, http, path_provider

More

Packages that depend on betuko_offline_sync