I am making a Tasks app where users type in their tasks for the day and they can check off a task once complete. To Store tasks, i am starting with an empty [ ] that gets populated with user's input. How do i save that data using shared preferences package and display each list item in a Listview, Here's my code :
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tooodo/views/task_lists_containers.dart';
class TasksScreen extends StatefulWidget {
const TasksScreen({Key? key}) : super(key: key);
@override
State<TasksScreen> createState() => _TasksScreenState();
}
class _TasksScreenState extends State<TasksScreen> {
// hard-coded a list of words. How do i get our to-do items from a database.
// the database will contain all user input.
List<String> toDoItems = [
'play',
'eat',
];
final TextEditingController _taskTextFieldController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: const Color.fromARGB(255, 7, 152, 70),
title: const Text('Tasks'),
centerTitle: true,
),
body: Container(
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
// ignore: prefer_const_literals_to_create_immutables
child: ListView.builder(
itemCount: toDoItems.length,
itemBuilder: (context, index) {
return TaskContainer(
child: toDoItems[index],
);
})),
// floating action bar and onpressed function
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Scaffold
return AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15))),
content: TextField(
controller: _taskTextFieldController,
textInputAction: TextInputAction.done,
decoration: InputDecoration(hintText: 'Task'),
),
actions: <Widget>[
TextButton(
child: Text("Save"),
onPressed: () {
toDoItems.add(_taskTextFieldController.text);
Navigator.of(context).pop();
_taskTextFieldController.clear();
setState(() {});
},
),
],
);
},
);
},
enableFeedback: true,
child: const Icon(Icons.add),
),
);
}
}
I welcome any advise pertaining to the code in terms of cleanliness and common standards am not following.
CodePudding user response:
You can follow this snippet, I am using getStringList
and setStringList
.
class TasksScreen extends StatefulWidget {
const TasksScreen({Key? key}) : super(key: key);
@override
State<TasksScreen> createState() => _TasksScreenState();
}
class _TasksScreenState extends State<TasksScreen> {
final TextEditingController _taskTextFieldController =
TextEditingController();
static const String listKey = "ITEMS";
Future<List<String>?> getItems() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getStringList(listKey) ?? [];
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: const Color.fromARGB(255, 7, 152, 70),
title: const Text('Tasks'),
centerTitle: true,
),
body: FutureBuilder<List<String>?>(
future: getItems(),
builder: (context, snapshot) {
return ListView.builder(
itemCount: snapshot.data?.length,
itemBuilder: (context, index) {
return Text(snapshot.data![index]);
},
);
}),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: FloatingActionButton(
onPressed: () async {
await showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Scaffold
return AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15))),
content: TextField(
controller: _taskTextFieldController,
textInputAction: TextInputAction.done,
decoration: InputDecoration(hintText: 'Task'),
),
actions: <Widget>[
TextButton(
child: Text("Save"),
onPressed: () async {
final prefs = await SharedPreferences.getInstance();
final oldItems = prefs.getStringList(listKey) ?? [];
await prefs.setStringList(listKey,
[...oldItems, _taskTextFieldController.text]);
Navigator.of(context).pop();
},
),
],
);
},
);
setState(() {}); //to rebuild the future builder , better way of doing it getting data from dialog and then update database and ui
},
enableFeedback: true,
child: const Icon(Icons.add),
),
);
}
}
CodePudding user response:
I created two functions:
To load from shared preferences:
List<String>? _toDoList;
Future<void> _loadToDoItems() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_toDoList = prefs.getStringList('toDoList') ?? [];
});
}
And to save to shared preferences:
_saveToDoItems() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setStringList('toDoList', _toDoList != null ? _toDoList! : []);
}
We call _loadToDoItems()
in initState
and _saveToDoItems()
within the TextButton()
:
TextButton(
child: Text("Save"),
onPressed: () {
// add the task to the list and save to shared preferences
setState(() {
_toDoList?.add(_taskTextFieldController.text);
_taskTextFieldController.clear();
_saveToDoItems();
});
Navigator.of(context).pop();
_taskTextFieldController.clear();
setState(() {});
},
),
Here is a complete runnable example (note: You'll have to fully stop your current project before using this snippet):
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: TasksScreen(),
),
),
);
}
}
class TasksScreen extends StatefulWidget {
const TasksScreen({Key? key}) : super(key: key);
@override
State<TasksScreen> createState() => _TasksScreenState();
}
class _TasksScreenState extends State<TasksScreen> {
List<String>? _toDoList;
Future<void> _loadToDoItems() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_toDoList = prefs.getStringList('toDoList') ?? [];
});
}
_saveToDoItems() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setStringList('toDoList', _toDoList != null ? _toDoList! : []);
}
final TextEditingController _taskTextFieldController =
TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: const Color.fromARGB(255, 7, 152, 70),
title: const Text('Tasks'),
centerTitle: true,
),
body: Container(
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
// ignore: prefer_const_literals_to_create_immutables
child: ListView.builder(
itemCount: _toDoList?.length,
itemBuilder: (context, index) {
return Container(
child: Text(_toDoList![index]),
);
})),
// floating action bar and onpressed function
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Scaffold
return AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15))),
content: TextField(
controller: _taskTextFieldController,
textInputAction: TextInputAction.done,
decoration: InputDecoration(hintText: 'Task'),
),
actions: <Widget>[
TextButton(
child: Text("Save"),
onPressed: () {
// add the task to the list and save to shared preferences
setState(() {
_toDoList?.add(_taskTextFieldController.text);
_taskTextFieldController.clear();
_saveToDoItems();
});
Navigator.of(context).pop();
_taskTextFieldController.clear();
setState(() {});
},
),
],
);
},
);
},
enableFeedback: true,
child: const Icon(Icons.add),
),
);
}
// load list from shared preferences
@override
void initState() {
_loadToDoItems();
super.initState();
}
}
Result: