flutter_sync_client 0.1.5
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();
}
}