Autocomplete suggestion and search using json data - json

I want to display data from local json in list as suggestions when user types in a textfield. The suggestions displayed should be based on id that is associated with text to be displayed.
Somehow I am not able to achieve to display the data in UI and how to build the hierarchy of widgets that will display suggestions in list. Not sure what am I missing here. Looking for guidance. End result I am looking to achieve is:
Json snippet:
{
"data": [{
"serviceCategory": "ELECTRICAL",
"serviceCategoryDesc": "Electrical",
"serviceCategoryId": 3,
"autocompleteTerm": "Accent Lighting Installation",
"category": "IMPROVEMENT",
Ex : If user types electrical, then autocompleteterm value should be displayed in the list.
For this, I created model class and fetching it's data which is displayed in console properly.
class Categories {
String serviceCategory;
String servCategoryDesc;
int id;
String autocompleteterm;
String category;
String desc;
Categories({
this.serviceCategory,
this.servCategoryDesc,
this.id,
this.autocompleteterm,
this.category,
this.desc
});
factory Categories.fromJson(Map<String, dynamic> parsedJson) {
return Categories(
serviceCategory: parsedJson['serviceCategory'] as String,
servCategoryDesc: parsedJson['serviceCategoryDesc'] as String,
id: parsedJson['serviceCategoryId'],
autocompleteterm: parsedJson['autocompleteTerm'] as String,
category: parsedJson['category'] as String,
desc: parsedJson['description'] as String
);
}
}
Code :
// Get json result and convert it to model. Then add
Future<String> getUserDetails() async {
String jsonData = await DefaultAssetBundle.of(context).loadString('assets/services.json');
Map data = json.decode(jsonData);
print(data);
setState(() {
final List<Categories> items = (data['data'] as List).map((i) => new Categories.fromJson(i)).toList();
for (final item in items) {
print(item.autocompleteterm);
}
});
}
GlobalKey<AutoCompleteTextFieldState<Categories>> key = new GlobalKey();
get categories => List<Categories>();
AutoCompleteTextField textField;
String currentText = "";
List<Categories> added = [];
#override
void initState() {
textField = AutoCompleteTextField<Categories>
(style: new TextStyle(
color: Colors.white,
fontSize: 16.0),
decoration: new InputDecoration(
suffixIcon: Container(
width: 85.0,
height: 60.0,
color:Colors.green,
child: new IconButton(
icon: new Image.asset('assets/search_icon_ivory.png',color: Colors.white,
height: 18.0,),
onPressed: (){},
),
),
fillColor: Colors.black,
contentPadding: EdgeInsets.fromLTRB(10.0, 30.0, 10.0, 20.0),
filled: true,
hintText: 'Search',
hintStyle: TextStyle(
color: Colors.white
)
),
itemSubmitted: null,
submitOnSuggestionTap: true,
clearOnSubmit: true,
textChanged: (item) {
currentText = item;
},
textSubmitted: (item) {
setState(() {
currentText = item;
added.add(widget.categories.firstWhere((i) => i.autocompleteterm.toLowerCase().contains(currentText)));
});
},
key: key,
suggestions: widget.categories,
itemBuilder: (context, item) {
return new Padding(
padding: EdgeInsets.all(8.0), child: new Text(item.autocompleteterm),
);
},
itemSorter: (a,b) {
return a.autocompleteterm.compareTo(b.autocompleteterm);
},
itemFilter: (item, query){
return item.autocompleteterm.toLowerCase().startsWith(query.toLowerCase());
});
super.initState();
_getUser();
getUserDetails();
}
#override
Widget build(BuildContext context) {
Column body = new Column(
children: <Widget>[
ListTile(
title: textField,
)
],
);
body.children.addAll(added.map((item) {
return ListTile(title: Text(item.autocompleteterm),
);
}
)
);
return Scaffold(
resizeToAvoidBottomPadding: false,
backgroundColor: Color(0xFF13212C),
appBar: AppBar(
title: Text('Demo'),
),
drawer: appDrawer(),
body: new Center(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new Column(
children: <Widget>[
textField,
]
),

The autocomplete_field package has been updated since this question was asked and now allows the use of objects other than Strings to work:
HomePage:
import 'package:flutter/material.dart';
import 'package:hello_world/category.dart';
import 'package:autocomplete_textfield/autocomplete_textfield.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => new _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<Category> added = [];
String currentText = "";
GlobalKey<AutoCompleteTextFieldState<Category>> key = new GlobalKey();
AutoCompleteTextField textField;
#override void initState() {
textField = new AutoCompleteTextField<Category>(
decoration: new InputDecoration(
hintText: "Search Item",
),
key: key,
submitOnSuggestionTap: true,
clearOnSubmit: true,
suggestions: CategoryViewModel.categories,
textInputAction: TextInputAction.go,
textChanged: (item) {
currentText = item;
},
itemSubmitted: (item) {
setState(() {
currentText = item.autocompleteterm;
added.add(item);
currentText = "";
});
},
itemBuilder: (context, item) {
return new Padding(
padding: EdgeInsets.all(8.0), child: new Text(item.autocompleteterm));
},
itemSorter: (a, b) {
return a.autocompleteterm.compareTo(b.autocompleteterm);
},
itemFilter: (item, query) {
return item.autocompleteterm.toLowerCase().startsWith(query.toLowerCase());
}
);
super.initState();
}
#override
Widget build(BuildContext context) {
Column body = new Column(children: [
new ListTile(
title: textField,
trailing: new IconButton(
icon: new Icon(Icons.add),
onPressed: () {
setState(() {
if (currentText != "") {
added.add(CategoryViewModel.categories.firstWhere((i) => i.autocompleteterm.toLowerCase().contains(currentText)));
textField.clear();
currentText = "";
}
});
}))
]);
body.children.addAll(added.map((item) {
return ListTile(title: Text(item.autocompleteterm), subtitle: Text(item.serviceCategory));
}));
return body;
}
}
Category classes:
import 'dart:convert';
import 'package:flutter/services.dart' show rootBundle;
class Category {
String serviceCategory;
String servCategoryDesc;
int id;
String autocompleteterm;
Category(
{this.serviceCategory,
this.servCategoryDesc,
this.id,
this.autocompleteterm});
factory Category.fromJson(Map<String, dynamic> parsedJson) {
return new Category(
serviceCategory: parsedJson['serviceCategory'],
servCategoryDesc: parsedJson['serviceCategoryDesc'],
id: parsedJson['serviceCategoryId'],
autocompleteterm: parsedJson['autocompleteTerm']);
}
}
class CategoryViewModel {
static List<Category> categories;
static Future loadCategories() async {
try {
categories = new List<Category>();
String jsonString = await rootBundle.loadString('assets/categories.json');
Map parsedJson = json.decode(jsonString);
var categoryJson = parsedJson['data'] as List;
for (int i = 0; i < categoryJson.length; i++) {
categories.add(new Category.fromJson(categoryJson[i]));
}
} catch (e) {
print(e);
}
}
}
Main with loading data:
void main() async {
await CategoryViewModel.loadCategories();
runApp(App());
}
Note, there are a few ways to load the data from the JSON but I find this way is easiest to do for a simple demo.

Related

Error in searching data using listview in flutter

I've tried this code for searching jobs in listview but the data is not shown in listview. I think JSON is not parsing properly for Jobs data.
Here is the code of the model:
import 'package:flutter/material.dart';
class JobItem {
final String title;
final String description;
JobItem(
{
required this.title,
required this.description,
});
factory JobItem.fromJson(Map<String, dynamic> json) {
return JobItem(
title: json['title'] as String,
description: json['description'] as String,
);
}
}
Here I've written code for the main file to search data from the listview.
List<JobItem> users = [];
List<JobItem> filteredUsers = [];
static String url = 'https://hospitality92.com/api/jobsbycategory/All';
static Future<List<JobItem>> getJobsData() async {
try {
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
List<JobItem> list = parseAgents(response.body);
return list;
} else {
throw Exception('Error');
}
} catch (e) {
throw Exception(e.toString());
}
}
static List<JobItem> parseAgents(String responseBody) {
final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<JobItem>((json) => JobItem.fromJson(json)).toList();
}
#override
void initState() {
super.initState();
getJobsData().then((usersFromServer) {
setState(() {
users = usersFromServer;
filteredUsers = users;
});
});
}```
Try below code your problem has been solved :
//declare packages
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
class Jobs extends StatefulWidget {
Jobs() : super();
#override
JobsState createState() => JobsState();
}
class Debouncer {
final int milliseconds;
VoidCallback action;
Timer _timer;
Debouncer({this.milliseconds});
run(VoidCallback action) {
if (null != _timer) {
_timer.cancel();
}
_timer = Timer(Duration(milliseconds: milliseconds), action);
}
}
class JobsState extends State<Jobs> {
final _debouncer = Debouncer(milliseconds: 500);
List<Subject> subjects = [];
List<Subject> filteredSubjects = [];
//API call for All Subject List
static String url = 'https://hospitality92.com/api/jobsbycategory/All';
static Future<List<Subject>> getAllSubjectsList() async {
try {
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
print(response.body);
List<Subject> list = parseAgents(response.body);
return list;
} else {
throw Exception('Error');
}
} catch (e) {
throw Exception(e.toString());
}
}
static List<Subject> parseAgents(String responseBody) {
final parsed =
json.decode(responseBody)['jobs'].cast<Map<String, dynamic>>();
return parsed.map<Subject>((json) => Subject.fromJson(json)).toList();
}
#override
void initState() {
super.initState();
getAllSubjectsList().then((subjectFromServer) {
setState(() {
subjects = subjectFromServer;
filteredSubjects = subjects;
});
});
}
//Main Widget
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'All Subjects',
style: TextStyle(fontSize: 25),
),
),
body: Column(
children: <Widget>[
//Search Bar to List of typed Subject
Container(
padding: EdgeInsets.all(15),
child: TextField(
textInputAction: TextInputAction.search,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: Colors.grey,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
borderSide: BorderSide(
color: Colors.blue,
),
),
suffixIcon: InkWell(
child: Icon(Icons.search),
),
contentPadding: EdgeInsets.all(15.0),
hintText: 'Search ',
),
onChanged: (string) {
_debouncer.run(() {
setState(() {
filteredSubjects = subjects
.where((u) => (u.title
.toLowerCase()
.contains(string.toLowerCase())))
.toList();
});
});
},
),
),
//Lists of Subjects
Expanded(
child: ListView.builder(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
padding: EdgeInsets.only(top: 20, left: 20, right: 20),
itemCount: filteredSubjects.length,
itemBuilder: (BuildContext context, int index) {
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
side: BorderSide(
color: Colors.grey[300],
),
),
child: Padding(
padding: EdgeInsets.all(5.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
ListTile(
leading: Text(
filteredSubjects[index].skills,
),
title: Text(
filteredSubjects[index].title,
style: TextStyle(fontSize: 16),
),
trailing: Text(filteredSubjects[index].position.toString()),
)
],
),
),
);
},
),
),
],
),
);
}
}
//Declare Subject class for json data or parameters of json string/data
//Class For Subject
class Subject {
String title;
int id;
String skills;
String position;
Subject({
this.id,
this.title,
this.skills,
this.position,
});
factory Subject.fromJson(Map<String, dynamic> json) {
return Subject(
title: json['title'] as String,
id: json['id'],
skills: json['skills'],
position: json['positions']);
}
}
Your screen before search:
Your Screen after search :
U have a little mistake in parsing. I added response.body['jobs'].
static Future<List<JobItem>> getJobsData() async {
try {
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
List<JobItem> list = parseAgents(Map<String, dynamic>.from(jsonDecode(response.body))['jobs']);
return list;
} else {
throw Exception('Error');
}
} catch (e) {
throw Exception(e.toString());
} }

type 'List<dynamic>' is not a subtype of type 'List<MaintenanceInfo>' of 'function result'

I want to change List data; (List < dynamic> data) to List<MaintenanceInfo> data;
class MaintenanceInfo {
final String serial;
MaintenanceInfo({this.serial,});
factory MaintenanceInfo.fromJson(Map<String, dynamic> json) {
return new MaintenanceInfo(
serial: json['serial'], );}}
Or is there any way to extract JSON data as forEach?
I am trying to follow this example (https://stackoverflow.com/a/50569613/12908336) and am facing such a problem.
Check out this example that i have created for you :
import 'dart:async';
import 'package:flutter/material.dart';
import 'dart:convert';
//import 'package:http/http.dart' as http;
void main() => runApp(new MaterialApp(
home: new HomePage(),
debugShowCheckedModeBanner: false,
));
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => new _HomePageState();
}
class _HomePageState extends State<HomePage> {
TextEditingController controller = new TextEditingController();
String apiData =
'''{"ResultText": "Success","ResultStatus": 0,"data": [{"serial": "sample1"},{"serial": "sample2"},{"serial": "sample3"},{"serial": "sample4"},{"serial": "sample5"},{"serial": "sample6"}]} ''';
// Get json result and convert it to model. Then add
Future<Null> getUserDetails() async {
// final response = await http.get(url);
// final responseJson = json.decode(response.body);
// this is where you apis gets hit i have taken the sample json you provided.
final maintenanceInfo = maintenanceInfoFromJson(apiData);
setState(() {
/* for (Map user in responseJson) {
_userDetails.add(UserDetails.fromJson(user));
} */
maintenanceInfo.data.forEach((element) {
_userDetails.add(element);
});
});
}
#override
void initState() {
super.initState();
getUserDetails();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Home'),
elevation: 0.0,
),
body: new Column(
children: <Widget>[
new Container(
color: Theme.of(context).primaryColor,
child: new Padding(
padding: const EdgeInsets.all(8.0),
child: new Card(
child: new ListTile(
leading: new Icon(Icons.search),
title: new TextField(
controller: controller,
decoration: new InputDecoration(
hintText: 'Search', border: InputBorder.none),
onChanged: onSearchTextChanged,
),
trailing: new IconButton(
icon: new Icon(Icons.cancel),
onPressed: () {
controller.clear();
onSearchTextChanged('');
},
),
),
),
),
),
new Expanded(
child: _searchResult.length != 0 || controller.text.isNotEmpty
? new ListView.builder(
itemCount: _searchResult.length,
itemBuilder: (context, i) {
return new Card(
child: new ListTile(
title: new Text(_searchResult[i].serial),
),
margin: const EdgeInsets.all(0.0),
);
},
)
: new ListView.builder(
itemCount: _userDetails.length,
itemBuilder: (context, index) {
return new Card(
child: new ListTile(
title: new Text(_userDetails[index].serial),
),
margin: const EdgeInsets.all(0.0),
);
},
),
),
],
),
);
}
onSearchTextChanged(String text) async {
_searchResult.clear();
if (text.isEmpty) {
setState(() {});
return;
}
_userDetails.forEach((userDetail) {
if (userDetail.serial.contains(text)) _searchResult.add(userDetail);
});
setState(() {});
}
}
List<Serials> _searchResult = [];
List<Serials> _userDetails = [];
// To parse this JSON data, do
//
// final maintenanceInfo = maintenanceInfoFromJson(jsonString);
MaintenanceInfo maintenanceInfoFromJson(String str) =>
MaintenanceInfo.fromJson(json.decode(str));
String maintenanceInfoToJson(MaintenanceInfo data) =>
json.encode(data.toJson());
class MaintenanceInfo {
MaintenanceInfo({
this.resultText,
this.resultStatus,
this.data,
});
String resultText;
int resultStatus;
List<Serials> data;
factory MaintenanceInfo.fromJson(Map<String, dynamic> json) =>
MaintenanceInfo(
resultText: json["ResultText"],
resultStatus: json["ResultStatus"],
data: List<Serials>.from(json["data"].map((x) => Serials.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"ResultText": resultText,
"ResultStatus": resultStatus,
"data": List<dynamic>.from(data.map((x) => x.toJson())),
};
}
class Serials {
Serials({
this.serial,
});
String serial;
factory Serials.fromJson(Map<String, dynamic> json) => Serials(
serial: json["serial"],
);
Map<String, dynamic> toJson() => {
"serial": serial,
};
}
Let me know if it works.

How to write new map with different values into json file without changing key in flutter?

I'm trying to add new content into a json as a map. It should look something like this:-
[
{
"title":"mon",
"date":"2/3/2020"
},
{
"title":"tue",
"date":"3/3/2020"
},
{
"title":"wed",
"date":"4/3/2020"
}
]
And I want show it in a listview. This is the code I use to create, write, and display:-
//new class
class WorkersLog extends StatefulWidget {
#override
_WorkersLogState createState() => _WorkersLogState();
}
class _WorkersLogState extends State<WorkersLog> {
#override
Widget build(BuildContext context) {
void _showSettingsPanel() {
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (context) {
return Container(
height: MediaQuery.of(context).size.height * .90,
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 40.0),
child: Center(child: WorkerCardData()),
);
});
}
return Container(
child: Column(
children: [
SizedBox(height: 40),
Padding(
padding: EdgeInsets.all(20.0),
child: Center(
child: Text(
"add document to store wages, loans etc of workers save paper,don't lose track of your accounts!"),
),
),
Row(
children: <Widget>[
Center(
child: Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(150, 350, 0, 5),
child: FloatingActionButton.extended(
label: Text('add document'),
icon: Icon(Icons.save),
backgroundColor: Colors.greenAccent,
elevation: 5.0,
onPressed: () {
print('object');
_showSettingsPanel();
},
),
),
],
),
),
],
),
],
),
);
}
}
//Create and write file to json
class WorkerCardData extends StatefulWidget {
#override
_WorkerCardDataState createState() => _WorkerCardDataState();
}
class _WorkerCardDataState extends State<WorkerCardData> {
TextEditingController title = new TextEditingController();
File jsonFile;
Directory dir;
String fileName = 'myFile.json';
bool fileExists = false;
Map<String, dynamic> fileContent;
#override
void initState() {
super.initState();
getApplicationDocumentsDirectory().then((Directory directory) {
dir = directory;
jsonFile = new File(dir.path + '/' + fileName);
fileExists = jsonFile.existsSync();
if (fileExists)
this.setState(
() => fileContent = json.decode(jsonFile.readAsStringSync()));
});
}
#override
void dispose() {
title.dispose();
super.dispose();
}
void createFile(
Map<String, dynamic> content, Directory dir, String fileName) {
print("Creating file!");
File file = new File(dir.path + "/" + fileName);
file.createSync();
fileExists = true;
file.writeAsStringSync(json.encode(content));
}
void writeToFile(String title, dynamic date) {
print("Writing to file!");
Map<String, dynamic> content = {'title': title, 'date': date};
if (fileExists) {
print("File exists");
Map<String, dynamic> jsonFileContent =
json.decode(jsonFile.readAsStringSync());
jsonFileContent.addAll(content);
jsonFile.writeAsStringSync(json.encode(jsonFileContent));
} else {
print("File does not exist!");
createFile(content, dir, fileName);
}
this.setState(() => fileContent = json.decode(jsonFile.readAsStringSync()));
print(fileContent);
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
new Padding(padding: new EdgeInsets.only(top: 10.0)),
new Text(
"File content: ",
style: new TextStyle(fontWeight: FontWeight.bold),
),
new Text(fileContent.toString()),
new Padding(padding: new EdgeInsets.only(top: 10.0)),
new Text("Add to JSON file: "),
new TextField(
controller: title,
decoration: textInputDecoration.copyWith(
hintText: 'title',
prefixIcon: Icon(Icons.info, color: Colors.white)),
),
new Padding(padding: new EdgeInsets.only(top: 20.0)),
new RaisedButton(
child: new Text("save new document"),
onPressed: () => writeToFile(title.text, DateTime.now().toString()),
)
],
),
);
}
}
//display json as list view
class WorkerCard extends StatefulWidget {
final String title;
WorkerCard({this.title});
#override
_WorkerCardState createState() => _WorkerCardState();
}
Directory dir;
Map<String, dynamic> workerFileContent;
File workerFile;
class _WorkerCardState extends State<WorkerCard> {
#override
void initState() {
super.initState();
getApplicationDocumentsDirectory().then((Directory directory) {
dir = directory;
workerFile = File(dir.path + 'myFile.json');
workerFileContent = json.decode(workerFile.readAsStringSync());
});
}
#override
Widget build(BuildContext context) {
return ListView.builder(
itemBuilder: (context, index) {
return Card(
child: Column(
children: [
Text(workerFileContent['title'].toString()),
Text(workerFileContent['date'].toString()),
],
),
);
},
);
}
}
Here's my problem. Each time I add new title, the file gets overwritten. How do I add a new map to my json file without overwriting previously added content?
loganrussell48 Thanks for guiding me to the answer
Change:-
Map<String, dynamic> fileContent;
To:-
List fileContent;

Flutter how to save list data locally

I am building a to-do list app and I would like to store the data locally such that every time I open the app, I get all the tasks that I had created previously. I am new to flutter and this is my first app. I already tried saving the data to a file, creating a JSON file to save the data and tried using a database. Nothing seems to work. Can someone help me with this?
This is my code: -
import 'package:flutter/material.dart';
class toDoList extends StatefulWidget
{
bool data = false;
#override
createState()
{
return new toDoListState();
}
}
class toDoListState extends State<toDoList>
{
List<String> tasks = [];
List<bool> completedTasks = [];
List<String> descriptions = [];
List<bool> importance = [];
#override
Widget build(BuildContext context)
{
return new Scaffold
(
body: buildToDoList(),
floatingActionButton: new FloatingActionButton
(
onPressed: addToDoItemScreen,
tooltip: 'Add Task',
child: new Icon(Icons.add),
),
);
}
Widget buildToDoList()
{
return new ListView.builder
(
itemBuilder: (context, index)
{
if(index < tasks.length)
{
if(tasks[index] == "#45jiodg{}}{OHU&IEB")
{
tasks.removeAt(index);
descriptions.removeAt(index);
importance.removeAt(index);
}
return row(tasks[index], descriptions[index], index);
};
},
);
}
Widget row(String task, String description, int index)
{
return Dismissible(
key: UniqueKey(),
background: Container(color: Colors.red, child: Align(alignment: Alignment.center, child: Text('DELETE', textAlign: TextAlign.center, style: TextStyle(color: Colors.white, fontSize: 18),))),
direction: DismissDirection.horizontal,
onDismissed: (direction) {
setState(() {
tasks.removeAt(index);
if(completedTasks[index])
{
completedTasks.removeAt(index);
}
descriptions.removeAt(index);
importance.removeAt(index);
});
Scaffold.of(context).showSnackBar(SnackBar(content: Text(task+" dismissed")));
},
child: CheckboxListTile(
controlAffinity: ListTileControlAffinity.leading,
title: Text(task, style: (completedTasks[index]) ? TextStyle(decoration: TextDecoration.lineThrough) : TextStyle(),),
subtitle: Text(descriptions[index], style: (completedTasks[index]) ? TextStyle(decoration: TextDecoration.lineThrough) : TextStyle(),),
isThreeLine: true,
secondary: (importance[index])? Icon(Icons.error, color: Colors.red,) : Text(''),
value: completedTasks[index],
onChanged: (bool value) {
setState(() {
if(completedTasks[index])
{
completedTasks[index] = false;
}
else
{
completedTasks[index] = true;
}
});
},
));
}
void addToDoItemScreen() {
int index = tasks.length;
while (importance.length > tasks.length) {
importance.removeLast();
}
importance.add(false);
tasks.add("#45jiodg{}}{OHU&IEB");
descriptions.add("No Description");
completedTasks.add(false);
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return StatefulBuilder(builder: (context, setState) { // this is new
return new Scaffold(
appBar: new AppBar(title: new Text('Add a new task')),
body: Form(
child: Column(
children: <Widget>[
TextField(
autofocus: true,
onSubmitted: (name) {
addToDoItem(name);
//Navigator.pop(context); // Close the add todo screen
},
decoration: new InputDecoration(
hintText: 'Enter something to do...',
contentPadding: const EdgeInsets.all(20.0),
border: OutlineInputBorder()),
),
TextField(
//autofocus: true,
//enabled: descriptions.length > desc,
onSubmitted: (val) {
addDescription(val, index);
},
decoration: new InputDecoration(
hintText: 'Enter a task decription...',
contentPadding: const EdgeInsets.all(20.0),
border: OutlineInputBorder()),
),
Row(
children: <Widget> [
Switch(
value: importance[index],
onChanged: (val) {
setState(() {
});
impTask(index);
},
),
Text('Important Task', style: TextStyle(fontSize: 18)),
],
),
RaisedButton(onPressed: () { Navigator.pop(context); }, child: Text('DONE', style: TextStyle(fontSize: 20)),)
],
),
));
});
}));
}
void addToDoItem(String task)
{
setState(() {
tasks.last = task;
});
}
void addDescription(String desc, int index)
{
setState(() {
descriptions.last = desc;
});
}
void impTask(int index)
{
setState(() {
if(importance[index])
{
importance[index] = false;
}
else
{
importance[index] = true;
}
});
}
}
I have 4 lists with the data. I need a simple way to save the lists such that the next time I open the app, the lists retain the data that was saved in them, the last time I had closed the app.
To do this you'll certainly have to use the path_provider package with this tutorial on the flutter.dev website. You should then be able to register a file and read it at the start of your application.
Once you have imported the path_provider and the dart:io packages, you can do something like this :
final directory = await getApplicationDocumentsDirectory();
final File file = File('${directory.path}/jsonObjects.json');
if (await file.exists()) {
json = await file.readAsString();
} else {
file.writeAsString(json);
}
First you get the application document directory ( the path ), then you create a File with the right path. Then if the file already exist, you read it, else you create it with the json you got and you should be good to go !

How to setState http url?

I want to create a news app and I've used newsapi.org as well but The
problem is actually that I want to make something like search feature in my
app and my idea is very simple.
I've created a TextField in the AppBar and my idea is to take the input from
user and setState with the new url of user input.
My Code:
import 'package:flutter/material.dart';
import 'package:newly/services/networking.dart';
import 'package:newly/widgets/article.dart';
class NewsScreen extends StatefulWidget {
#override
_NewsScreenState createState() => _NewsScreenState();
}
class _NewsScreenState extends State<NewsScreen> {
List<Article> articles = [];
String topic = 'google';
var newsData;
Future getNews(String topic) async {
NetworkHelper networkHelper = NetworkHelper(
url:
'https://newsapi.org/v2/everything?q=$topic&from=2019-11-04&to=2019-11-04&sortBy=popularity&apiKey=392495172bab4b3885ae93760df54b91',
);
newsData = await networkHelper.getData();
for (int i = 0; i < newsData['articles'].length; i++) {
var title = newsData['articles'][i]['title'];
var urlToImage = newsData['articles'][i]['urlToImage'];
var content = newsData['articles'][i]['content'];
var author = newsData['articles'][i]['author'];
var url = newsData['articles'][i]['url'];
setState(() {
articles.add(
Article(
author: author,
content: content,
title: title,
url: url,
urlToImage: urlToImage,
),
);
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
centerTitle: true,
title: TextField(
textInputAction: TextInputAction.search,
onChanged: (String text) async {
setState(() {
topic = text;
});
await getNews(topic);
print(topic);
},
onSubmitted: (String text) async {
setState(() {
topic = text;
});
print(topic);
await getNews(topic);
},
decoration: InputDecoration(
suffixIcon: IconButton(
onPressed: () async {
await getNews(topic);
print(topic);
},
icon: Icon(
Icons.search,
),
),
hintText: 'Search',
filled: true,
fillColor: Colors.white,
),
),
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: FutureBuilder(
future: getNews(topic),
builder: (context, snapshot) {
return ListView.builder(
itemCount: newsData['articles'] == null
? 0
: newsData['articles'].length,
itemBuilder: (BuildContext ctxt, int index) {
return Article(
author: articles[index].author,
content: articles[index].content,
title: articles[index].title,
url: articles[index].url,
urlToImage: articles[index].urlToImage,
);
},
);
},
),
),
),
);
}
}
Network Helper :
import 'package:http/http.dart' as http;
import 'dart:convert';
class NetworkHelper {
NetworkHelper({this.url});
final String url;
Future getData() async {
http.Response response = await http.get(url);
if (response.statusCode == 200) {
String data = response.body;
return json.decode(data);
} else {
print('something wrong');
print(response.statusCode);
}
}
}