flutter_data_sync 0.0.5 flutter_data_sync: ^0.0.5 copied to clipboard
flutter_data_sync simplifies the mapping between Flutter app models and external data sources (API, DB). Easily transform JSON data into Dart objects and manage HTTP requests, reducing development tim [...]
// ignore_for_file: avoid_print, use_build_context_synchronously, must_be_immutable
import 'package:flutter/material.dart';
import 'package:flutter_data_sync/flutter_data_sync.dart';
void main() {
runApp(const MyApp());
}
DataSync dataSync = DataSync(baseApiUrl: "http://127.0.0.1:8080/api/");
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Todo list -- Flutter data sync demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int deletingID = 0;
int validatingID = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Padding(
padding: const EdgeInsets.all(30.0),
child: DataSyncGetWidget<List<Todo>>(
setIntervallCall: false,
setIntervallCallDuration: const Duration(seconds: 2),
onSetIntervall: (timer) {},
promise: () => dataSync.index<Todo>(
context: context,
fromJson: Todo.fromJson,
url: "todos",
),
hasDataWidget: (data) {
return ListView.builder(
shrinkWrap: true,
itemCount: data.length,
itemBuilder: (BuildContext context, int index) {
Todo todo = data[index];
return ListTile(
leading: validatingID == todo.id
? SizedBox(
width: 15,
height: 15,
child: DataSyncLoading.loadingBallRotate(
color: Colors.blue[800]!))
: Checkbox(
value: todo.isValid,
onChanged: (value) async {
setState(() {
validatingID = todo.id ?? 0;
});
todo.isValid = value!;
await valideCheckTodo(todo);
}),
title: Text(todo.libelle),
subtitle: Text(todo.description),
trailing: Wrap(
children: [
IconButton(
onPressed: () async {
if (await showAddTodoModal(
context: context, todo: todo) !=
null) {
setState(() {});
}
},
icon: Icon(
Icons.edit,
color: Colors.green[800],
),
),
deletingID == todo.id
? SizedBox(
width: 20,
height: 20,
child: DataSyncLoading.loadingBallRotate(
color: Colors.red[800]!))
: IconButton(
onPressed: () async {
setState(() {
deletingID = todo.id ?? 0;
});
await valideDeleteTodo(todo);
},
icon: Icon(
Icons.delete_forever_outlined,
color: Colors.red[800],
),
),
],
),
onTap: () {
print('Item $index tapped');
},
);
});
}),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
if (await showAddTodoModal(
context: context, todo: Todo.fromJson({})) !=
null) {
setState(() {});
}
},
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
valideDeleteTodo(Todo todo) async {
bool etat = await dataSync.delete<Todo, bool>(
context: context,
fromJson: (map, statusCode) =>
statusCode == 200 || statusCode == 201 ? true : false,
url: "todos/${todo.id}",
);
if (etat) {
setState(() {
deletingID = 0;
});
Navigator.pop(context);
} else {
setState(() {
deletingID = 0;
});
}
}
valideCheckTodo(Todo todo) async {
bool etat = await dataSync.put<Todo, bool>(
context: context,
fromJson: (map, statusCode) =>
statusCode == 200 || statusCode == 201 ? true : false,
url: "todos/${todo.id}",
data: todo.toJSon());
if (etat) {
setState(() {
validatingID = 0;
});
} else {
setState(() {
validatingID = 0;
});
}
}
}
showAddTodoModal({required context, required Todo todo}) async {
await showDialog(
barrierDismissible: false,
context: context,
builder: (context) {
return AlertDialog(
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(5)),
),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"Ajouter une Todo",
style: TextStyle(
color: Colors.black87,
fontSize: 17,
fontWeight: FontWeight.bold),
),
const SizedBox(width: 300),
IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(Icons.close, color: Colors.blueGrey[400]))
],
),
titlePadding:
const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
contentPadding:
const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
content: AddTodo(todo: todo),
elevation: 1,
);
});
return Todo;
}
class AddTodo extends StatefulWidget {
Todo todo;
AddTodo({super.key, required this.todo});
@override
State<AddTodo> createState() => _AddTodoState();
}
class _AddTodoState extends State<AddTodo> {
final _keyForm = GlobalKey<FormState>();
bool _isloading = false;
bool updateState = false;
@override
void initState() {
super.initState();
if (widget.todo.id != null) {
updateState = true;
} else {
updateState = false;
}
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
constraints: const BoxConstraints(minWidth: 300, maxWidth: 500),
width: 500,
child: Form(
key: _keyForm,
child: Card(
color: Colors.transparent,
elevation: 0,
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
initialValue: widget.todo.libelle,
decoration: const InputDecoration(hintText: "Libellé"),
validator: (val) => val.toString().isEmpty
? "veuillez entrer un nom de Todo valide !"
: null,
onChanged: (val) {
widget.todo.libelle = val;
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
initialValue: widget.todo.description,
maxLines: 3,
decoration: const InputDecoration(hintText: "Description"),
onChanged: (val) {
widget.todo.description = val;
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: CheckboxListTile(
title: const Text("Cette tâche est achevée !"),
value: widget.todo.isValid,
onChanged: (value) {
setState(() {
widget.todo.isValid = value!;
});
})),
const SizedBox(
height: 15,
),
Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: MaterialButton(
onPressed: () {
Navigator.pop(context);
},
elevation: 0,
color: const Color.fromARGB(255, 240, 240, 240),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
padding: const EdgeInsets.symmetric(
horizontal: 20, vertical: 17),
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Annuler",
style: TextStyle(
color: Colors.black87,
fontSize: 15,
),
),
],
)),
),
const SizedBox(
width: 8,
),
Expanded(
child: MaterialButton(
onPressed: () async {
FocusScope.of(context).unfocus();
if (_keyForm.currentState!.validate()) {
setState(() {
_isloading = true;
});
if (!updateState) {
await valideAddTodo();
} else {
valideUpdateTodo();
}
}
},
elevation: 0,
color: updateState
? Colors.green[700]
: Colors.blue[700],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
padding: const EdgeInsets.symmetric(
horizontal: 20, vertical: 17),
child: _isloading
? Center(
child: DataSyncLoading.loadingPulse(
color: Colors.white,
bg: Colors.transparent))
: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
updateState ? "Modifier" : "Ajouter",
style: const TextStyle(
color: Colors.white,
fontSize: 15,
),
),
],
)),
),
],
),
),
const SizedBox(
height: 15,
),
],
),
),
),
),
);
}
valideAddTodo() async {
bool state = await dataSync.post<Todo, bool>(
context: context,
fromJson: (map, statusCode) =>
statusCode == 200 || statusCode == 201 ? true : false,
url: "todos",
data: widget.todo.toJSon());
if (state) {
setState(() {
_isloading = false;
});
Navigator.pop(context);
} else {
setState(() {
_isloading = false;
});
}
}
valideUpdateTodo() async {
bool etat = await dataSync.put<Todo, bool>(
context: context,
fromJson: (map, statusCode) =>
statusCode == 200 || statusCode == 201 ? true : false,
url: "todos/${widget.todo.id}",
data: widget.todo.toJSon());
if (etat) {
setState(() {
_isloading = false;
});
Navigator.pop(context);
} else {
setState(() {
_isloading = false;
});
}
}
}
class Todo {
int? id;
String libelle = "";
String description = "";
bool isValid = false;
Todo({required this.libelle, required this.description});
factory Todo.fromJson(json) {
Todo todo = Todo(
libelle: json['libelle'] ?? "", description: json['description'] ?? "");
todo.id = json['id'];
todo.isValid = json['isValid'] ?? false;
return todo;
}
Map<String, dynamic> toJSon() => {
'libelle': libelle,
'description': description,
'isValid': isValid ? 1 : 0
};
}