betuko_offline_sync 3.0.0 copy "betuko_offline_sync: ^3.0.0" to clipboard
betuko_offline_sync: ^3.0.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 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.0.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();

📖 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