fero_sync 0.4.9 copy "fero_sync: ^0.4.9" to clipboard
fero_sync: ^0.4.9 copied to clipboard

Fero - Flutter Sync Orchestration SDK by StarsGathered

example/lib/main.dart

import 'dart:async';
import 'package:fero_sync/fero_sync.dart';
import 'package:fero_sync/core/models/sync_checkpoint.dart';
import 'package:fero_sync/core/models/sync_payload.dart';
import 'package:fero_sync/core/models/syncable.dart';
import 'package:fero_sync/core/results/apply_result.dart';
import 'package:fero_sync/core/results/sync_batch_result.dart';
import 'package:fero_sync/core/sync_metadata_repo.dart';
import 'package:fero_sync/feature_sync/feature_sync_config.dart';
import 'package:fero_sync/feature_sync/feature_sync_handler.dart';
import 'package:fero_sync/initial_sync/enum/initial_sync_status.dart';
import 'package:fero_sync/initial_sync/initial_sync.dart';
import 'package:fero_sync/initial_sync/initial_sync_handler.dart';

/// ------------------
/// Entry Point
/// ------------------
Future<void> main() async {
  // Local in-memory database
  final localDb = <LocalMessage>[];

  // Initialize FeroSync with initial and background sync handlers
  final feroSync = await FeroSync.create(
    metadataRepo: InMemorySyncMetaDataRepo(),
    initialSyncConfigs: {
      "messages": InitialSyncConfig(
        handler: MessageInitialSyncHandler(localDb),
      ),
    },
    featureSyncConfigs: {
      "messages": FeatureSyncConfig(
        handler: MessageFeatureSyncHandler(localDb),
      ),
    },
  );

  // Listen for initial sync status
  feroSync.initialSyncNotifier.addListener(() {
    print("📊 Initial Sync Status: ${feroSync.initialSyncNotifier.value}");
    if (feroSync.initialSyncNotifier.value == InitialSyncStatus.completed) {
      print(
          "✅ Initial sync completed! Local DB has ${localDb.length} messages.");
    }
  });

  // Only sync feature that need initial. if initial sync already completed, it will immediately update status notifier.
  feroSync.startInitialSync();

  // Listen for background/incremental sync updates
  feroSync.featureSyncNotifier("messages")?.addListener(() {
    print("📡 Background Sync Running...");
  });

  // Simulate user adding a message
  addMessageFromUI("Hello, world!", localDb, feroSync);
}

/// ------------------
/// Local & Server Models
/// ------------------
class LocalMessage implements LocalItem {
  @override
  final String id;
  final String text;
  @override
  final int version;
  @override
  final bool locallyModified;

  LocalMessage({
    required this.id,
    required this.text,
    required this.version,
    this.locallyModified = false,
  });
}

class ServerMessage implements ServerItem {
  @override
  final String id;
  @override
  final BigInt syncId;
  final String text;
  @override
  final int version;
  @override
  final DateTime updatedAt;

  ServerMessage({
    required this.id,
    required this.syncId,
    required this.text,
    required this.version,
    required this.updatedAt,
  });
}

/// ------------------
/// Initial Sync Handler
/// ------------------
class MessageInitialSyncHandler extends InitialSyncHandler {
  final List<LocalMessage> _localDb;

  MessageInitialSyncHandler(this._localDb);

  @override
  Future<SyncBatchResult> fetchRemoteData({
    checkpoint,
    required int batchSize,
  }) async {
    print("🌍 Fetching messages from server...");

    // Simulated server messages
    final serverMessages = [
      ServerMessage(
        id: "m1",
        syncId: BigInt.from(1),
        text: "Welcome 👋",
        version: 1,
        updatedAt: DateTime.parse("2024-01-01T00:00:00Z"),
      ),
    ];

    return SyncBatchResult.success(
      items: serverMessages
          .map((msg) => SyncPayload<ServerItem>(data: msg))
          .toList(),
      checkpoint: SyncCheckpoint(
        lastSyncedId: BigInt.from(1),
        lastSyncedAt: "2024-01-01T00:00:00Z",
      ), // last synced message info for next incremental fetches
    );
  }

  @override
  Future<ApplyResult> saveToLocal(
      List<SyncPayload<ServerItem>> remoteData) async {
    for (final payload in remoteData) {
      final server = payload.data as ServerMessage;
      _localDb.add(LocalMessage(
        id: server.id,
        text: server.text,
        version: server.version,
        locallyModified: false,
      ));
    }
    print("💾 Initial messages saved locally");
    return ApplyResult.success();
  }
}

/// ------------------
/// Feature (Background) Sync Handler
/// ------------------
class MessageFeatureSyncHandler extends FeatureSyncHandler {
  final List<LocalMessage> _localDb;

  MessageFeatureSyncHandler(this._localDb);

  @override
  Future<List<SyncPayload<LocalItem>>> getLocallyModified(
      {int batchSize = 50}) async {
    final modified = _localDb
        .where((m) => m.locallyModified)
        .take(batchSize)
        .map((m) => SyncPayload<LocalItem>(data: m))
        .toList();
    print("📤 Found ${modified.length} unsent messages");
    return modified;
  }

  @override
  Future<ApplyResult> pushLocalChanges(
      [List<SyncPayload<LocalItem>>? localStates]) async {
    print("🚀 Sending ${localStates?.length ?? 0} messages to server...");
    for (final payload in localStates ?? []) {
      final msg = payload.data as LocalMessage;
      final index = _localDb.indexWhere((e) => e.id == msg.id);
      if (index != -1) {
        _localDb[index] = LocalMessage(
          id: msg.id,
          text: msg.text,
          version: msg.version + 1,
          locallyModified: false,
        );
      }
    }
    return ApplyResult.success();
  }

  @override
  Future<SyncBatchResult> fetchRemoteChanges(
      {checkpoint, required int batchSize}) async {
    print("🌍 Fetching new messages from server...");
    final newMessages = [
      ServerMessage(
        id: "m2",
        syncId: BigInt.from(2),
        text: "Hello from server!",
        version: 1,
        updatedAt: DateTime.parse("2024-01-01T00:00:00Z"),
      ),
    ];

    return SyncBatchResult.success(
      items: newMessages.map((e) => SyncPayload<ServerItem>(data: e)).toList(),
      checkpoint: SyncCheckpoint(
        lastSyncedId: BigInt.from(2),
        lastSyncedAt: "2024-01-01T00:00:00Z",
      ), // last synced message info for next incremental fetches
    );
  }

  @override
  Future<ApplyResult> applyRemoteChanges(
      List<SyncPayload<ServerItem>> remoteData) async {
    for (final payload in remoteData) {
      final server = payload.data as ServerMessage;
      if (!_localDb.any((m) => m.id == server.id)) {
        _localDb.add(LocalMessage(
          id: server.id,
          text: server.text,
          version: server.version,
          locallyModified: false,
        ));
      }
    }
    print("📥 Applied ${remoteData.length} new messages locally");
    return ApplyResult.success();
  }

  @override
  Future<List<SyncPayload<LocalItem>>> getLocallyModifiedByIds(
      {required List<String> ids}) async {
    return _localDb
        .where((m) => ids.contains(m.id))
        .map((m) => SyncPayload<LocalItem>(data: m))
        .toList();
  }
}

/// ------------------
/// In-Memory Metadata Repository
/// ------------------
class InMemorySyncMetaDataRepo implements SyncMetaDataRepo {
  final Map<String, SyncCheckpoint?> _checkpoints = {};
  final Map<String, bool> _initialCompleted = {};

  @override
  Future<SyncCheckpoint?> getCheckpoint(String featureKey) async =>
      _checkpoints[featureKey];

  @override
  Future<void> updateCheckpoint(
          String featureKey, SyncCheckpoint? checkpoint) async =>
      _checkpoints[featureKey] = checkpoint;

  @override
  Future<bool> isInitialSyncCompleted(String featureKey) async =>
      _initialCompleted[featureKey] ?? false;

  @override
  Future<bool> areAllInitialSyncsCompleted(List<String> featureKeys) async =>
      featureKeys.every((key) => _initialCompleted[key] ?? false);

  @override
  Future<void> setInitialSyncCompleted(
          String featureKey, bool completed) async =>
      _initialCompleted[featureKey] = completed;
}

/// ------------------
/// Helper: Add message from UI
/// ------------------
void addMessageFromUI(
    String text, List<LocalMessage> localDb, FeroSync feroSync) {
  final newMessage = LocalMessage(
    id: DateTime.now().millisecondsSinceEpoch.toString(),
    text: text,
    version: 1,
    locallyModified: true,
  );
  localDb.add(newMessage);
  print("✏️ User added message locally: ${newMessage.text}");

  // Force immediate sync for this feature
  feroSync.syncFeature("messages", force: true);
}
1
likes
160
points
813
downloads

Publisher

verified publisherstarsgathered.com

Weekly Downloads

Fero - Flutter Sync Orchestration SDK by StarsGathered

Homepage
Repository (GitHub)
View/report issues

Documentation

Documentation
API reference

License

MIT (license)

Dependencies

cupertino_icons, flutter

More

Packages that depend on fero_sync