sync_repository 1.2.0 copy "sync_repository: ^1.2.0" to clipboard
sync_repository: ^1.2.0 copied to clipboard

Offline-first sync layer for Flutter apps. Wraps a remote repository with a local SharedPreferences store and a SyncRepository.

example/lib/main.dart

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

void main() {
  runApp(const GenericApp());
}

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

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

class InMemoryRepository implements OfsRepository {
  final List<OfsTask> _items = [];

  @override
  Future<List<OfsTask>> getDailyTasks() async {
    await Future.delayed(const Duration(milliseconds: 300));
    return List<OfsTask>.from(_items);
  }

  @override
  Future<void> addDaily(String title) async {
    await Future.delayed(const Duration(milliseconds: 200));
    _items.add(OfsTask(
      id: DateTime.now().millisecondsSinceEpoch.toString(),
      title: title,
      dayOfWeek: Weekday.any,
      isDone: false,
    ));
  }

  @override
  Future<void> editDaily(String itemId, String title) async {
    await Future.delayed(const Duration(milliseconds: 200));
    final idx = _items.indexWhere((t) => t.id == itemId);
    if (idx != -1) _items[idx] = _items[idx].copyWith(title: title);
  }

  @override
  Future<void> deleteDaily(String itemId) async {
    await Future.delayed(const Duration(milliseconds: 200));
    _items.removeWhere((t) => t.id == itemId);
  }

  @override
  Future<void> toggleDaily(String itemId, bool isDone) async {
    await Future.delayed(const Duration(milliseconds: 200));
    final idx = _items.indexWhere((t) => t.id == itemId);
    if (idx != -1) _items[idx] = _items[idx].copyWith(isDone: isDone);
  }

  // Other methods not implemented for brevity
  @override
  Future<List<OfsTask>> getWeeklyTasks() async => [];
  @override
  Future<List<OfsTask>> getDeadlineTasks() async => [];
  @override
  Future<List<OfsTask>> getQuestTasks() async => [];
  @override
  Future<OfsSettings?> getSettings() async => null;
  @override
  Future<void> addWeekly(String title, Weekday day) async {}
  @override
  Future<void> addDeadline(
      String title, DateTime date, TimeOfDay? time) async {}
  @override
  Future<void> addQuest(String title) async {}
  @override
  Future<void> editWeekly(String taskId, String title, Weekday day) async {}
  @override
  Future<void> editDeadline(
      String taskId, String title, DateTime date, TimeOfDay? time) async {}
  @override
  Future<void> editQuest(String taskId, String title) async {}
  @override
  Future<void> deleteWeekly(String taskId) async {}
  @override
  Future<void> deleteDeadline(String taskId) async {}
  @override
  Future<void> deleteQuest(String taskId) async {}
  @override
  Future<void> toggleWeekly(String taskId, bool isDone) async {}
  @override
  Future<void> saveDailyOrder(List<String> orderedTaskIds) async {}
  @override
  Future<void> saveQuestOrder(List<String> orderedTaskIds) async {}
  @override
  Future<void> saveWeeklyAnyOrder(List<String> orderedTaskIds) async {}
}

class GenericHome extends StatefulWidget {
  @override
  State<GenericHome> createState() => _GenericHomeState();
}

class _GenericHomeState extends State<GenericHome> {
  late final SharedPrefsLocalStore localStore;
  late final InMemoryRepository remoteRepo;
  late final SyncRepository syncRepo;
  final TextEditingController inputController = TextEditingController();
  List<OfsTask> items = [];

  @override
  void initState() {
    super.initState();
    localStore = SharedPrefsLocalStore();
    remoteRepo = InMemoryRepository();
    syncRepo = SyncRepository(remote: remoteRepo, local: localStore);
    syncRepo.isSyncingNotifier.addListener(_onSyncingChanged);
    _loadItems();
  }

  void _onSyncingChanged() {
    setState(() {});
  }

  Future<void> _loadItems() async {
    final loaded = await syncRepo.getDailyTasks();
    setState(() {
      items = loaded;
    });
  }

  Future<void> _addItem(String title) async {
    await syncRepo.addDaily(title);
    inputController.clear();
    await _loadItems();
  }

  Future<void> _toggleItem(OfsTask item) async {
    await syncRepo.toggleDaily(item.id, !item.isDone);
    await _loadItems();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Offline First Sync Example'),
        actions: [
          ValueListenableBuilder<bool>(
            valueListenable: syncRepo.isSyncingNotifier,
            builder: (context, syncing, child) {
              return Padding(
                padding: const EdgeInsets.symmetric(horizontal: 16),
                child: Row(
                  children: [
                    const Text('Syncing'),
                    Icon(
                      syncing ? Icons.sync : Icons.check,
                      color: syncing ? Colors.orange : Colors.green,
                    ),
                  ],
                ),
              );
            },
          ),
        ],
      ),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: inputController,
                    decoration: const InputDecoration(
                      labelText: 'Add an item',
                    ),
                  ),
                ),
                IconButton(
                  icon: const Icon(Icons.add),
                  onPressed: () {
                    if (inputController.text.trim().isNotEmpty) {
                      _addItem(inputController.text.trim());
                    }
                  },
                ),
              ],
            ),
          ),
          Expanded(
            child: ListView.builder(
              itemCount: items.length,
              itemBuilder: (context, idx) {
                final item = items[idx];
                return ListTile(
                  title: Text(item.title),
                  leading: Checkbox(
                    value: item.isDone,
                    onChanged: (_) => _toggleItem(item),
                  ),
                  trailing: IconButton(
                    icon: const Icon(Icons.delete),
                    onPressed: () async {
                      await syncRepo.deleteDaily(item.id);
                      await _loadItems();
                    },
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}
0
likes
150
points
15
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Offline-first sync layer for Flutter apps. Wraps a remote repository with a local SharedPreferences store and a SyncRepository.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, meta, shared_preferences

More

Packages that depend on sync_repository