flutter_sync_client 0.1.5 copy "flutter_sync_client: ^0.1.5" to clipboard
flutter_sync_client: ^0.1.5 copied to clipboard

Real-time data synchronization plugin for Flutter with Hive and Socket.IO

example/lib/main.dart

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  final syncClient = SyncClient(
    serverUrl: 'http://localhost:3000',
  );
  await syncClient.initialize();

  runApp(MyApp(syncClient: syncClient));
}

class MyApp extends StatelessWidget {
  final SyncClient syncClient;

  const MyApp({Key? key, required this.syncClient}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sync Client Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: TodoListPage(syncClient: syncClient),
    );
  }
}

class TodoListPage extends StatefulWidget {
  final SyncClient syncClient;

  const TodoListPage({Key? key, required this.syncClient}) : super(key: key);

  @override
  State<TodoListPage> createState() => _TodoListPageState();
}

class _TodoListPageState extends State<TodoListPage> {
  late CollectionReference todosCollection;
  final TextEditingController _textController = TextEditingController();

  @override
  void initState() {
    super.initState();
    todosCollection = widget.syncClient.collection('todos');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Todo List'),
        actions: [
          StreamBuilder<bool>(
            stream: widget.syncClient.connectionStream,
            initialData: false,
            builder: (context, snapshot) {
              final isConnected = snapshot.data ?? false;
              return Icon(
                isConnected ? Icons.cloud_done : Icons.cloud_off,
                color: isConnected ? Colors.green : Colors.red,
              );
            },
          ),
          const SizedBox(width: 16),
        ],
      ),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _textController,
                    decoration: const InputDecoration(
                      hintText: 'Enter todo title',
                      border: OutlineInputBorder(),
                    ),
                  ),
                ),
                const SizedBox(width: 8),
                ElevatedButton(
                  onPressed: _addTodo,
                  child: const Text('Add'),
                ),
              ],
            ),
          ),
          Expanded(
            child: StreamBuilder<List<Map<String, dynamic>>>(
              stream: todosCollection.stream,
              builder: (context, snapshot) {
                if (!snapshot.hasData) {
                  return const Center(child: CircularProgressIndicator());
                }

                final todos = snapshot.data!;

                if (todos.isEmpty) {
                  return const Center(child: Text('No todos yet'));
                }

                return ListView.builder(
                  itemCount: todos.length,
                  itemBuilder: (context, index) {
                    final todo = todos[index];
                    final isCompleted = todo['completed'] ?? false;

                    return ListTile(
                      leading: Checkbox(
                        value: isCompleted,
                        onChanged: (value) => _toggleTodo(todo['id'], value!),
                      ),
                      title: Text(
                        todo['title'] ?? '',
                        style: TextStyle(
                          decoration: isCompleted
                              ? TextDecoration.lineThrough
                              : null,
                        ),
                      ),
                      trailing: IconButton(
                        icon: const Icon(Icons.delete),
                        onPressed: () => _deleteTodo(todo['id']),
                      ),
                    );
                  },
                );
              },
            ),
          ),
        ],
      ),
    );
  }

  Future<void> _addTodo() async {
    if (_textController.text.trim().isEmpty) return;

    await todosCollection.add({
      'title': _textController.text.trim(),
      'completed': false,
      'createdAt': DateTime.now().millisecondsSinceEpoch,
    });

    _textController.clear();
  }

  Future<void> _toggleTodo(String id, bool completed) async {
    await todosCollection.update(id, {
      'completed': completed,
    });
  }

  Future<void> _deleteTodo(String id) async {
    await todosCollection.delete(id);
  }

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