Change url using SearchDelegate - json

Flutter
I want to change the end of the url in my project, I used SearchDelegate for this, but I can't change it, my codes are as follows
Search code
enter code here
class Arama extends SearchDelegate {
Future<List<Model>>? apilistfuture;
#override
List<Widget>? buildActions(BuildContext context) {
return [
IconButton(
onPressed: () {
query = '';
},
icon: const Icon(
Icons.close,
color: Colors.red,
),
),
];
}
#override
Widget? buildLeading(BuildContext context) {
return IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: const Icon(
Icons.arrow_back_ios,
color: Colors.black,
),
);
}
#override
Widget buildResults(BuildContext context) {
return FutureBuilder<List<Model>>(
future: apilistfuture,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Model> _listem = snapshot.data!;
return ListView.builder(
itemCount: _listem.length,
itemBuilder: (context, index) {
var oankiApi = _listem[index];
return ListTile(
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Tanım: ${oankiApi.description}'),
Text('Ekran Senbol: ${oankiApi.displaySymbol}'),
Text('Senbol: ${oankiApi.symbol}'),
Text('Tip: ${oankiApi.type}'),
],
),
);
},
);
} else if (snapshot.hasError) {
return const Center(
child: Text('hata'),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
);
}
#override
Widget buildSuggestions(BuildContext context) {
return const Center(
child: Text(
'Arama..',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
);
}
}
home code
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
Future<List<Model>>? apilistfuture;
#override
void initState() {
apilistfuture = Api.getapiData();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
showSearch(context: context, delegate: Arama());
},
icon: const Icon(Icons.search),
),
],
backgroundColor: Colors.blue,
),
body: FutureBuilder<List<Model>>(
future: apilistfuture,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Model> _listem = snapshot.data!;
return ListView.builder(
itemCount: _listem.length,
itemBuilder: (context, index) {
var oankiApi = _listem[index];
return ListTile(
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Tanım: ${oankiApi.description}'),
Text('Ekran Senbol: ${oankiApi.displaySymbol}'),
Text('Senbol: ${oankiApi.symbol}'),
Text('Tip: ${oankiApi.type}'),
],
),
);
},
);
} else if (snapshot.hasError) {
return const Center(
child: Text('hata'),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
);
}
}
In the project, expressions such as string, int will come to the place where the value is written at the end of the url, how can I bring the value?
api code
class Api {
static Future<List<Model>> getapiData({String? deger}) async {
String url = 'http://10.0.2.2:5000/symbol_lookup?search=${deger}';
List<Model> list = [];
var result = await Dio().get(url);
var apiList = jsonDecode(result.data)['result'];
if (apiList is List) {
list = apiList.map((e) => Model.fromJson(e)).toList();
//sonradan eklendi
if (deger != null) {
list = list
.where((element) => element.description!
.toLowerCase()
.contains(deger.toLowerCase()))
.toList();
}
} else {
return [];
}
debugPrint(list.length.toString());
return list;
}
}
Int, string texts will be followed by an equal sign at the end of the url, for example, values ​​such as 'https://login=search' will come. Could you help me find the problem? I tried a few things but it comes up blank
enter image description here
enter image description here
As you can see in the pictures, I get an error when I call.

Related

data isn't reflected on the app from database when I enter new data and return to this page

The data from mysql server isn't automatically reflected in my app when I fill a form to enter the data from my app and comeback to the page... But if I login again or do a hot reload the data is reflected and I'm not sure where to add a setState({}) and what to write inside of it so please tell me how to update my list automatically.........
import 'dart:convert';
import 'package:finance_returns/Screens/Admin/AdminLogin.dart';
import 'package:finance_returns/Screens/Admin/CreateUser.dart';
import 'package:finance_returns/constants.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:http/http.dart' as http;
class AdminDashboard extends StatefulWidget {
#override
_AdminDashboardState createState() => _AdminDashboardState();
}
class _AdminDashboardState extends State<AdminDashboard> {
Future getData() async {
var url = Uri.parse('http://$ip/EmployeesDB/admin/read.php');
var response = await http.get(url);
return json.decode(response.body);
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Dashboard'),
actions: <Widget>[
IconButton(
icon: Icon(FontAwesomeIcons.signOutAlt),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AdminLogin(),
),
);
})
],
),
floatingActionButton: Container(
margin: EdgeInsets.only(bottom: 10),
child: FloatingActionButton.extended(
backgroundColor: kPrimaryColor,
onPressed: () {
Navigator.push( context, MaterialPageRoute( builder: (context) => Register()), ).then((list) => setState);
},
icon: Icon(
Icons.add,
),
label: Text("User"))),
body: FutureBuilder(
future: getData(),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData
? ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
List list = snapshot.data;
return ListTile(
//leading: GestureDetector(
//child: Icon(Icons.mode_edit_outline),
onTap: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => Register(
list: list,
index: index,
),
),
);
debugPrint('Edit Clicked');
},
//),
title: Text(list[index]['username']),
subtitle: Text(list[index]['level']),
trailing: GestureDetector(
child: Icon(Icons.delete),
onTap: () {
setState(() {
var url =
Uri.parse('http://$ip/EmployeesDB/admin/delete.php');
http.post(url, body: {
'id': list[index]['id'],
});
});
debugPrint('delete Clicked');
},
),
);
})
: CircularProgressIndicator();
},
)
);
}
}
This is the registration page:
import 'dart:convert';
import 'package:finance_returns/Screens/Admin/AdminDashboard.dart';
import 'package:finance_returns/components/text_field_container.dart';
import 'package:finance_returns/constants.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart' as http;
class Register extends StatefulWidget {
final List list;
final int index;
Register({this.list, this.index});
#override
_RegisterState createState() => _RegisterState();
}
class _RegisterState extends State<Register> {
TextEditingController name = TextEditingController();
TextEditingController user = TextEditingController();
TextEditingController pass = TextEditingController();
TextEditingController level = TextEditingController();
bool editMode = false;
Future addUpdateData() async {
if (editMode) {
var url = Uri.parse("http://$ip/EmployeesDB/admin/edit.php");
http.post(url, body: {
'id': widget.list[widget.index]['id'],
"name": name.text,
"username": user.text,
"password": pass.text,
"level": level.text,
});
} else {
var url = Uri.parse("http://$ip/EmployeesDB/admin/user_register.php");
var response = await http.post(url, body: {
"name": name.text,
"username": user.text,
"password": pass.text,
"level": level.text,
});
var data = json.decode(response.body);
if (data == "Error") {
Fluttertoast.showToast(
msg: "This user already exists!",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
} else {
Fluttertoast.showToast(
msg: "Successfully registered",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.green,
textColor: Colors.white,
fontSize: 16.0);
// Navigator.pop(
// context,
// MaterialPageRoute(
// builder: (context) => AdminDashboard(),
// ),
// );
}
}
}
#override
void initState() {
super.initState();
if (widget.index != null) {
editMode = true;
name.text = widget.list[widget.index]['name'];
user.text = widget.list[widget.index]['username'];
pass.text = widget.list[widget.index]['password'];
level.text = widget.list[widget.index]['level'];
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Create/Update Users',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
body: SingleChildScrollView(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextFieldContainer(
child: TextField(
decoration: InputDecoration(
labelText: 'Name',
icon: Icon(
Icons.person,
color: kPrimaryColor,
),
border: InputBorder.none,
),
controller: name,
),
),
TextFieldContainer(
child: TextField(
decoration: InputDecoration(
labelText: 'Email id',
icon: Icon(
Icons.person,
color: kPrimaryColor,
),
border: InputBorder.none,
),
controller: user,
),
),
TextFieldContainer(
child: TextField(
obscureText: true,
decoration: InputDecoration(
labelText: 'Password',
icon: Icon(
Icons.lock,
color: kPrimaryColor,
),
border: InputBorder.none,
),
controller: pass,
),
),
TextFieldContainer(
child: TextField(
decoration: InputDecoration(
labelText: 'level (eg:member,admin,HR)',
icon: Icon(
Icons.person,
color: kPrimaryColor,
),
border: InputBorder.none,
),
controller: level,
),
),
MaterialButton(
color: kPrimaryColor,
child: Text(editMode ? 'Update' : 'Create',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white)),
onPressed: () {
setState(() {
addUpdateData();
});
Navigator.pop(
context,
MaterialPageRoute(
builder: (context) => AdminDashboard(),
),
);
debugPrint('Clicked Button Button');
},
),
],
),
),
),
);
}
}
I think you are doing the navigation before getting data and that setState is updating the state of the current page, not the previous one. Try this:
onPressed: () async {
await addUpdateData();
}
and in the first page:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Register(
list: list,
index: index,
),
),
).then((_) => setState(() {});

Flutter get snapshot.data[1] in future builder

I have the following code
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter_form_builder/flutter_form_builder.dart';
class MyData {
String title;
String days;
String words;
String rep;
String gender;
var username;
MyData({this.gender, this.title, this.days, this.words, this.rep, this.username,
});
}
class StepperBody extends StatefulWidget {
#override
_StepperBodyState createState() => _StepperBodyState();
}
class _StepperBodyState extends State<StepperBody> {
int currStep = 0;
static var _focusNode = FocusNode();
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
Future<List<String>> _future;
Future<List<String>> _car;
List<GlobalKey<FormState>> formKeys = [
GlobalKey<FormState>(),
GlobalKey<FormState>(),
GlobalKey<FormState>(),
GlobalKey<FormState>()
];
String _key = "786465659081B207EB5BF1EF9AF7552A6";
String _api = "https://10.0.2.2/api/";
Future<void> senddata(List<String> username) async {
final response = await http.post(
_api + "insert_data.php?key=" + _key, body: {
"username": username,
});
var resp = jsonDecode(response.body);
print(resp.toString());
}
Future<List<String>> getData() async {
var url = _api + "get_data.php?key=" + _key;
http.Response response = await http.get(url);
var resp = jsonDecode(response.body);
print(resp.toString());
return resp.map<String>((m) => m['username'] as String).toList();
}
Future<List<String>> getCar() async {
var url = _api + "get_car.php?key=" + _key;
http.Response response = await http.get(url);
var resp = jsonDecode(response.body);
print(resp.toString());
return resp.map<String>((m) => m['plate'] as String).toList();
}
#override
void initState() {
super.initState();
_future = getData();
_car = getCar();
_focusNode.addListener(() {
setState(() {});
print('Has focus: $_focusNode.hasFocus');
});
}
#override
Widget build(BuildContext context) {
void showSnackBarMessage(String message,
[MaterialColor color = Colors.red]) {
Scaffold.of(context).showSnackBar(SnackBar(content: Text(message)));
}
void _submitDetails(List<String> username) {
final FormState formState = _formKey.currentState;
final FormBuilderState fbKeyState = _fbKey.currentState;
/*
_fbKey.currentState.save();
if (_fbKey.currentState.validate()) {
print(_fbKey.currentState.value);
}
*/
if (!fbKeyState.validate()) {
showSnackBarMessage('Please enter correct data');
senddata(username);
} else {
showSnackBarMessage('Saved');
formState.save();
senddata(username);
print("Name: $username");
_fbKey.currentState.save();
if (_fbKey.currentState.validate()) {
print(_fbKey.currentState.value);
}
}
}
return FutureBuilder<List<String>>(
future: Future.wait([_future, _car]),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
final steps = [
Step(
title: const Text('Users'),
//subtitle: const Text('Subtitle'),
isActive: true,
//state: StepState.editing,
state: StepState.indexed,
content: Form(
key: formKeys[0],
child: Column(
children: <Widget>[
FormBuilder(
key: _fbKey,
autovalidate: true,
child: FormBuilderCheckboxList(
decoration:
InputDecoration(labelText: "Languages you know"),
attribute: "languages",
initialValue: ["English"],
options: snapshot.data[0]
.map((languages) => FormBuilderFieldOption(
value: languages, child: Text("$languages")))
.toList(),
),
),
],
),
),
),
Step(
title: const Text('Users'),
//subtitle: const Text('Subtitle'),
isActive: true,
//state: StepState.editing,
state: StepState.indexed,
content: Form(
key: formKeys[1],
child: Column(
children: <Widget>[
FormBuilder(
key: _fbKey,
autovalidate: true,
child: FormBuilderCheckboxList(
decoration:
InputDecoration(labelText: "Cars"),
attribute: "cars",
initialValue: ["BM-WD01"],
options: snapshot.data[1]
.map((car) => FormBuilderFieldOption(
value: car, child: Text("$car")))
.toList(),
),
),
],
),
),
),
];
return Container(
child: Form(
key: _formKey,
child: ListView(children: <Widget>[
Stepper(
steps: steps,
physics: ClampingScrollPhysics(),
type: StepperType.vertical,
currentStep: this.currStep,
onStepContinue: () {
setState(() {
if (formKeys[currStep].currentState.validate()) {
if (currStep < steps.length - 1) {
currStep = currStep + 1;
} else {
currStep = 0;
}
}
// else {
// Scaffold
// .of(context)
// .showSnackBar( SnackBar(content: Text('$currStep')));
// if (currStep == 1) {
// print('First Step');
// print('object' + FocusScope.of(context).toStringDeep());
// }
// }
});
},
controlsBuilder: (BuildContext context,
{VoidCallback onStepContinue, VoidCallback onStepCancel}) {
return Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
//
RaisedButton(
color: Colors.red,
child: Text("Forward",
style: TextStyle(color: Colors.white)),
onPressed: onStepContinue,
),
SizedBox(width: 15,),
RaisedButton(
color: Colors.red,
child: Text(
"Back", style: TextStyle(color: Colors.white)),
onPressed: onStepCancel,
),
],
);
},
onStepCancel: () {
setState(() {
if (currStep > 0) {
currStep = currStep - 1;
} else {
currStep = 0;
}
});
},
onStepTapped: (step) {
setState(() {
currStep = step;
});
},
),
RaisedButton(
child: Text(
'Save',
style: TextStyle(color: Colors.white),
),
onPressed: () {
var submitDetails = _submitDetails;
submitDetails(snapshot.data);
},
color: Colors.lightGreen,
),
]),
));
} else {
return CircularProgressIndicator();
}
}
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: "test",),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
MyAppScreenMode createState() => MyAppScreenMode();
}
class MyAppScreenMode extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new MaterialApp(
theme: new ThemeData(
primarySwatch: Colors.red,
),
home: new Scaffold(
appBar: new AppBar(
title: new Text('Test stepper'),
),
body: new StepperBody(),
));
}
}
I want to display multiple lists from mySQL, the first function _future works fine, but when I replace future: _future to
future: Future.wait([_future, _car]),
I get an
The element type 'Future<List>' can't be assigned to the list
type 'Future'
I have tried lots of other solutions but none of them works to use snapshot.data[0], snapshot.data1 and so on for more queries and data to display from different tables.
Can't get to work with more futurebuilders which would be even easier for each step own, but then I get
Step(
title: const Text('Users'),
//subtitle: const Text('Subtitle'),
isActive: true,
//state: StepState.editing,
state: StepState.indexed,
content: Form(
key: formKeys[0],
child: FutureBuilder<List>(
future: _future,
// ignore: missing_return
builder: (BuildContext context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
Column(
children: <Widget>[
FormBuilder(
key: _fbKey,
autovalidate: true,
child: FormBuilderCheckboxList(
decoration:
InputDecoration(
labelText: "Languages you know"),
attribute: "languages",
initialValue: ["English"],
options: snapshot.data
.map((gender) =>
FormBuilderFieldOption(
value: gender, child: Text("$gender")))
.toList(),
),
),
],
);
}
}
),
),
),
];
Any help would be appreciated.
The working solution for the question. If there is any better way feel free to post :)
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter_form_builder/flutter_form_builder.dart';
class MyData {
String title;
String days;
String words;
String rep;
String gender;
var username;
MyData(
{this.gender, this.title, this.days, this.words, this.rep, this.username,
});
}
class StepperBody extends StatefulWidget {
#override
_StepperBodyState createState() => _StepperBodyState();
}
class _StepperBodyState extends State<StepperBody> {
int currStep = 0;
static var _focusNode = FocusNode();
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
Future<List<String>> _future;
Future<List<String>> _getcar;
List<GlobalKey<FormState>> formKeys = [
GlobalKey<FormState>(),
GlobalKey<FormState>(),
GlobalKey<FormState>(),
GlobalKey<FormState>()
];
String _key = "786465659081B207EB5BF1EF9AF7552A6";
String _api = "https://10.0.2.2/api/";
Future<void> senddata() async {
final response = await http.post(
_api + "insert_data.php?key=" + _key, body: {
});
var resp = jsonDecode(response.body);
print(resp.toString());
}
Future<List<String>> getData() async {
var url = _api + "get_data.php?key=" + _key;
http.Response response = await http.get(url);
var resp = jsonDecode(response.body);
print(resp.toString());
return resp.map<String>((m) => m['username'] as String).toList();
}
Future<List<String>> getCar() async {
var url = _api + "get_car.php?key=" + _key;
http.Response response = await http.get(url);
var resp = jsonDecode(response.body);
print(resp.toString());
return resp.map<String>((m) => m['plate'] as String).toList();
}
Widget getdis2(BuildContext context) {
return FutureBuilder<List<String>>(
future: _getcar, // a previously-obtained Future<String> or null
builder: (BuildContext context, AsyncSnapshot<List<String>> snapshot) {
List<Widget> children;
if (snapshot.hasData) {
children = <Widget>[
FormBuilderCheckboxList(
decoration:
InputDecoration(
labelText: "Languages you know"),
attribute: "languages",
initialValue: ["English"],
options: snapshot.data
.map((gender) =>
FormBuilderFieldOption(
value: gender, child: Text("$gender")))
.toList(),
),
];
} else if (snapshot.hasError) {
children = <Widget>[
Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
)
];
} else {
children = <Widget>[
SizedBox(
child: CircularProgressIndicator(),
width: 60,
height: 60,
),
const Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
];
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
),
);
},
);
}
Widget getdis(BuildContext context) {
return FutureBuilder<List<String>>(
future: _future, // a previously-obtained Future<String> or null
builder: (BuildContext context, AsyncSnapshot<List<String>> snapshot) {
List<Widget> children;
if (snapshot.hasData) {
children = <Widget>[
FormBuilderCheckboxList(
decoration:
InputDecoration(
labelText: "Languages you know"),
attribute: "languages",
initialValue: ["English"],
options: snapshot.data
.map((gender) =>
FormBuilderFieldOption(
value: gender, child: Text("$gender")))
.toList(),
),
];
} else if (snapshot.hasError) {
children = <Widget>[
Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
)
];
} else {
children = <Widget>[
SizedBox(
child: CircularProgressIndicator(),
width: 60,
height: 60,
),
const Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
];
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
),
);
},
);
}
#override
void initState() {
super.initState();
_future = getData();
_getcar = getCar();
_focusNode.addListener(() {
setState(() {});
print('Has focus: $_focusNode.hasFocus');
});
}
#override
Widget build(BuildContext context) {
void showSnackBarMessage(String message,
[MaterialColor color = Colors.red]) {
Scaffold.of(context).showSnackBar(SnackBar(content: Text(message)));
}
void _submitDetails() {
final FormState formState = _formKey.currentState;
final FormBuilderState fbKeyState = _fbKey.currentState;
/*
_fbKey.currentState.save();
if (_fbKey.currentState.validate()) {
print(_fbKey.currentState.value);
}
*/
if (!fbKeyState.validate()) {
showSnackBarMessage('Please enter correct data');
senddata();
} else {
showSnackBarMessage('Saved');
formState.save();
senddata();
print("Name: ");
_fbKey.currentState.save();
if (_fbKey.currentState.validate()) {
print(_fbKey.currentState.value);
}
}
}
final steps = [
Step(
title: const Text('Users'),
//subtitle: const Text('Subtitle'),
isActive: true,
//state: StepState.editing,
state: StepState.indexed,
content: Form(
key: formKeys[0],
child: getdis(context),
),
),
Step(
title: const Text('Cars'),
//subtitle: const Text('Subtitle'),
isActive: true,
//state: StepState.editing,
state: StepState.indexed,
content: Form(
key: formKeys[1],
child: getdis2(context),
),
),
];
return Container(
child: Form(
key: _formKey,
child: ListView(children: <Widget>[
Stepper(
steps: steps,
physics: ClampingScrollPhysics(),
type: StepperType.vertical,
currentStep: this.currStep,
onStepContinue: () {
setState(() {
if (formKeys[currStep].currentState.validate()) {
if (currStep < steps.length - 1) {
currStep = currStep + 1;
} else {
currStep = 0;
}
}
// else {
// Scaffold
// .of(context)
// .showSnackBar( SnackBar(content: Text('$currStep')));
// if (currStep == 1) {
// print('First Step');
// print('object' + FocusScope.of(context).toStringDeep());
// }
// }
});
},
controlsBuilder: (BuildContext context,
{VoidCallback onStepContinue, VoidCallback onStepCancel}) {
return Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
//
RaisedButton(
color: Colors.red,
child: Text("Forward",
style: TextStyle(color: Colors.white)),
onPressed: onStepContinue,
),
SizedBox(width: 15,),
RaisedButton(
color: Colors.red,
child: Text(
"Back", style: TextStyle(color: Colors.white)),
onPressed: onStepCancel,
),
],
);
},
onStepCancel: () {
setState(() {
if (currStep > 0) {
currStep = currStep - 1;
} else {
currStep = 0;
}
});
},
onStepTapped: (step) {
setState(() {
currStep = step;
});
},
),
RaisedButton(
child: Text(
'Save',
style: TextStyle(color: Colors.white),
),
onPressed: () {
var submitDetails = _submitDetails;
submitDetails();
},
color: Colors.lightGreen,
),
]),
));
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: "test",),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
MyAppScreenMode createState() => MyAppScreenMode();
}
class MyAppScreenMode extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new MaterialApp(
theme: new ThemeData(
primarySwatch: Colors.red,
),
home: new Scaffold(
appBar: new AppBar(
title: new Text('Test stepper'),
),
body: new StepperBody(),
));
}
}
Im not sure about this, but in my understanding, a FutureBuilder expects exactly 1 future. the returned value of this future is accessable with "snapshot.data".
If you need to wait for multiple futures to resolve, I propose you use multiple FutureBuilders.
Another way would be to use Future.wait() somewhere else and return all required data as one Furure from there.

How to generate a list of cards based on the number of items in json file

I use the following code to generate 10 predefined cards on a flutter screen which doesn't change:
List cards = new List.generate(10, (i)=>new QuestionCard()).toList();
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('My First App'),
backgroundColor:new Color(0xFF673AB7),
),
body: new Container(
child: new ListView(
children: cards,
)
)
);
}
}
class QuestionCard extends StatefulWidget {
#override
_QuestionCardState createState() => _QuestionCardState();
}
class _QuestionCardState extends State<QuestionCard> {
#override
Widget build(BuildContext context) {
return Container(
child: Card(
borderOnForeground: true,
color: Colors.green,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const ListTile(
trailing: Icon(Icons.album),
title: Text('Q1'),
subtitle: Text('What is the name of this location?'),
),
new TextFormField(
decoration: new InputDecoration(
labelText: "Answer Question",
fillColor: Colors.white,
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(25.0),
borderSide: new BorderSide(
),
),
//fillColor: Colors.green
),
validator: (val) {
if(val.length==0) {
return "Type your answer here";
}else{
return null;
}
},
keyboardType: TextInputType.text,
style: new TextStyle(
fontFamily: "Poppins",
),
),
ButtonBar(
children: <Widget>[
FlatButton(
child: const Text('Save'),
onPressed: () {/* ... */},
),
],
),
],
),
),
);
}
}
My json is simple (questions.json):
{
"Questions":
[
{
"id" : 1,
"quest" : ["question one"]
},
{
"id" : 2,
"quest" : ["question two", "question three"]
},
{
"id" : 3,
"quest" : ["question four"]
},
{
"id" : 4,
"quest" : ["question five", "question six", "question seven"]
}
]
}
So I have 2 questions I need to solve:
1. If I have more than 1 question I'll need to add an additional text box for a response for which I'll use a different card type, 2, 3, 4 max, which I'll need to define once.
But my real question here:
How do I generate the list based on the json response:
Future _loadQuestionAssets() async
{
return await rootBundle.loadString('assets/questions.json');
}
Future loadQuestion() async{
String jsonString = await _loadQuestionAssets();
final jsonResponse = json.decode(jsonString);
Questions question = new Questions.fromJson(jsonResponse);
//List cards = new List.generate(length, generator)
}
try this:
class MyFirstApp extends StatefulWidget{
#override
createState()=> new _appState();
}
class _appState extends State<MyFirstApp>{
List _displayData;
//assuming that you saved your json file in your assets folder
loadJson() async {
String data = await rootBundle.loadString('assets/json/questions.json');
jsonResult = json.decode(data);
print(jsonResult);
setState((){
_displayData = jsonResult["Questions"];
});
}
#override
void initState(){
super.initState();
loadJson();
}
#override
Widget build(BuildContext context){
return Scaffold(
appbar: Appbar(
title: Text("My APP")
),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: _displayData == null ? Center(child: CircularProgressIndicator()) :
ListView.builder(
itemcount: _displayData.length,
itembuilder: (context, index){
return Container(
width: MediaQuery.of(context).size.width,
height: 80,
margin: EdgeInsets.only(bottom: 5),
child: Text(_displayData[index]["id"])
);
}
)
)
);
}
}

How to create a gridview within a listview by flutter with json API

I'd like to create a shopping cart app
I had a problem
How to create a GridView within a ListView by flutter with JSON API
I want it exactly like this Example :
https://i.stack.imgur.com/2KQFG.png
https://i.stack.imgur.com/I0gY8.gif
--- Update ----
About SliverGrid
I tried to fetch the products but an error appeared (This is regarding the SliverGrid part)
I/flutter ( 5992): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 5992): The following assertion was thrown building FutureBuilder<List<dynamic>>(dirty, state:
I/flutter ( 5992): _FutureBuilderState<List<dynamic>>#78747):
I/flutter ( 5992): A build function returned null.
I/flutter ( 5992): The offending widget is: FutureBuilder<List<dynamic>>
I/flutter ( 5992): Build functions must never return null. To return an empty space that causes the building widget to
I/flutter ( 5992): fill available room, return "new Container()". To return an empty space that takes as little room as
I/flutter ( 5992): possible, return "new Container(width: 0.0, height: 0.0)".
With regard to ListView (It works fine)..
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
Future<List<dynamic>> getCategoriesApi() async {
http.Response response1 =
await http.get("http://159.89.228.206/");
Map<String, dynamic> decodedCategories = json.decode(response1.body);
//print(response1);
return decodedCategories['categories'];
}
Future<List<dynamic>> getProductsApi() async {
http.Response response =
await http.get("http://159.89.228.206/");
Map<String, dynamic> decodedCategories2 = json.decode(response.body);
// print(response);
return decodedCategories2['last'];
}
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(title: 'Sliver Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ScrollController _scrollController = new ScrollController();
List<dynamic> products;
List<dynamic> categories;
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: Column(children: <Widget>[
Expanded(
child: CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverToBoxAdapter(
child: SizedBox(
height: 120.0,
child: FutureBuilder(
future: getCategoriesApi(),
builder: (BuildContext context,
AsyncSnapshot<List<dynamic>> snapshot) {
if (snapshot.connectionState ==
ConnectionState.done) {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
Map<String, String> category =
snapshot.data[index].cast<String, String>();
return Card(
child: Container(
height: double.infinity,
color: Colors.grey[200],
child: Center(
child: Padding(
padding: EdgeInsets.all(30.0),
child: Text(category["name"]),
),
),
),
);
},
itemCount: snapshot.data.length,
);
} else {
return Center(child: CircularProgressIndicator());
}
}),
),
),
SliverToBoxAdapter(
child: Container(
child: FutureBuilder(
future: getProductsApi(),
builder: (BuildContext context,
AsyncSnapshot<List<dynamic>> snapshot) {
if (snapshot.connectionState ==
ConnectionState.done) {
SliverGrid(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.8,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
Map<String, String> product = snapshot
.data[index]
.cast<String, String>();
return Card(
child: Container(
height: double.infinity,
color: Colors.grey[200],
child: Center(
child: Padding(
padding: EdgeInsets.all(30.0),
child: Text(product["name"]),
),
),
),
);
},
childCount: snapshot.data.length,
),
);
} else {
return Center(child: CircularProgressIndicator());
}
}),
),
),
],
),
)
]));
}
}
You can't embed a GridView directly in a ListView unless you play with the height reserved for the GridView. If you want to maintain the scroll for both sections as you show in your images, the best thing is to use a CustomScrollView and Slivers.
After the image is my proposal.
import 'dart:convert';
import 'package:flutter/material.dart';
String productsJson =
'{"last": [{"product_id":"62","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, '
'{"product_id":"61","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, '
'{"product_id":"57","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, '
'{"product_id":"63","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, '
'{"product_id":"64","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, '
'{"product_id":"58","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, '
'{"product_id":"59","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}]}';
String categoriesJson = '{"categories":['
'{"name":"Category 1","image":"icon.png","id":2}, '
'{"name":"Category 2","image":"icon.png","id":4}, '
'{"name":"Category 3","image":"icon.png","id":4}, '
'{"name":"Category 4","image":"icon.png","id":4}, '
'{"name":"Category 5","image":"icon.png","id":6}]}';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'Sliver Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ScrollController _scrollController = ScrollController();
List<dynamic> products;
List<dynamic> categories;
#override
initState() {
super.initState();
Map<String, dynamic> decoded = json.decode(productsJson);
products = decoded['last'];
Map<String, dynamic> decodedCategories = json.decode(categoriesJson);
categories = decodedCategories['categories'];
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverToBoxAdapter(
child: SizedBox(
height: 120.0,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
Map<String, String> category =
categories[index].cast<String, String>();
return Card(
child: Container(
height: double.infinity,
color: Colors.grey[200],
child: Center(
child: Padding(
padding: EdgeInsets.all(30.0),
child: Text(category["name"]),
),
),
),
);
},
itemCount: categories.length,
),
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.8,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
Map<String, String> product =
products[index].cast<String, String>();
return Card(
child: Container(
color: Colors.grey[400],
child: Padding(
padding: EdgeInsets.symmetric(vertical: 30.0),
child: Center(
child: Text("Product ${product["product_id"]}")),
),
),
);
},
childCount: products.length,
),
),
],
),
);
}
}
If you want to retrieve the json from the network you can add/replace the following code. Add a method that returns a Future and then build the ListView using a FutureBuilder.
....
import 'package:http/http.dart' as http;
import 'dart:async';
....
Future<List<dynamic>> getCategories() async {
http.Response response = await http.get("http://159.89.228.206");
Map<String, dynamic> decodedCategories = json.decode(response.body);
return decodedCategories['categories'];
}
...
...
SliverToBoxAdapter(
child: SizedBox(
height: 120.0,
child: FutureBuilder(
future: getCategories(),
builder: (BuildContext context, AsyncSnapshot<List<dynamic>> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
Map<String, String> category =
snapshot.data[index].cast<String, String>();
return Card(
child: Container(
height: double.infinity,
color: Colors.grey[200],
child: Center(
child: Padding(
padding: EdgeInsets.all(30.0),
child: Text(category["name"]),
),
),
),
);
},
itemCount: snapshot.data.length,
);
} else {
return Center(child: CircularProgressIndicator());
}
}),
),
),
....
The simple answer to this would be Tabs .
Render Tabs dynamically as per your category and under render GridView in TabView.
Here is Output :
Here is the Code :
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Shopping App',
theme: ThemeData(
primarySwatch: Colors.orange,
),
home: ShowProductScreen(),
);
}
}
class Product {
String productId;
String image;
String name;
String price;
Product({this.productId, this.image, this.name, this.price});
}
class Category {
String id;
String name;
String image;
List<Product> productList;
Category({this.id, this.name, this.image, this.productList});
}
class ShowProductScreen extends StatefulWidget {
#override
_ShowProductScreenState createState() => _ShowProductScreenState();
}
class _ShowProductScreenState extends State<ShowProductScreen> with TickerProviderStateMixin {
List<Category> categoryList = List();
TabController _tabController;
#override
void initState() {
super.initState();
//Add data
for (int i = 0; i < 10; i++) {
List<Product> productList = List();
for (int j = 0; j < 50; j++) {
Product product = Product(
productId: "$i-$j",
price: "${(j + 1) * 10}",
name: "Product $i-$j",
image: "assets/image.jpg",
);
productList.add(product);
}
Category category = Category(
id: "$i",
name: "Category $i",
image: "assets/image.jpg",
productList: productList,
);
categoryList.add(category);
}
_tabController = TabController(vsync: this, length: categoryList.length);
}
#override
void dispose() {
super.dispose();
_tabController.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
titleSpacing: 0.0,
title: IconButton(
icon: Icon(
Icons.shopping_cart,
),
onPressed: () {},
),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.menu,
),
onPressed: () {},
)
],
),
body: Column(
children: <Widget>[
Container(
height: 100.0,
child: TabBar(
controller: _tabController,
isScrollable: true,
tabs: categoryList.map((Category category) {
return CategoryWidget(
category: category,
);
}).toList(),
),
),
Expanded(
child: Container(
padding: EdgeInsets.all(5.0),
child: TabBarView(
controller: _tabController,
children: categoryList.map((Category category) {
return Container(
child: GridView.count(
crossAxisCount: 2,
childAspectRatio: 4 / 3,
controller: ScrollController(keepScrollOffset: false),
scrollDirection: Axis.vertical,
children: category.productList.map(
(Product product) {
return ProductWidget(
product: product,
);
},
).toList(),
),
);
}).toList(),
),
),
)
],
),
);
}
}
class CategoryWidget extends StatelessWidget {
final Category category;
const CategoryWidget({Key key, this.category}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(4.0),
child: Image(
image: AssetImage(category.image),
height: 60.0,
),
),
Text(category.name)
],
),
);
}
}
class ProductWidget extends StatelessWidget {
final Product product;
const ProductWidget({Key key, this.product}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(4.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(8.0),
),
border: Border.all(
color: Colors.orange,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Image(
image: AssetImage(product.image),
fit: BoxFit.contain,
height: 80.0,
),
Text(product.name)
],
),
);
}
}
Hope it Helps!

How can you access the documentId for a particular recipe in Firestore using Flutter?

#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(
"Comments",
style: TextStyle(color: Colors.white),
),
backgroundColor: primaryColor,
),
body: StreamBuilder(
stream: Firestore.instance.collection('recipes').document('MXYt6fLDt5F4I1XJen31').collection('comments').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if(!snapshot.hasData) return CircularProgressIndicator();
return FirestoreListView( documents: snapshot.data.documents);
},
),
);
}
}
class FirestoreListView extends StatelessWidget {
final List<DocumentSnapshot> documents;
FirestoreListView({this.documents});
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: documents.length,
itemBuilder: (BuildContext context, int index){
String message = documents[index].data['message'].toString();
return ListTile(
title: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(color: Colors.black),
),
padding: EdgeInsets.all(5.0),
child: Row(
children: <Widget>[
Expanded(
child: Text(message),
),
]
),
)
);
},
);
}
}
Firestore.instance.collection('recipes').document('MXYt6fLDt5F4I1XJen31').collection('comments').snapshots()
Here as you can see I'm accessing an already existing recipe with her corresponding Id. I want to go to the detail page and then leave a comment that is only going to be shown for that recipe. So I need to access that UNIC id.
You can try something like this using the forEach method:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: StreamBuilder(
stream: Firestore.....your_path....collection('comments').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<DocumentSnapshot> documentSnapshotsList =
snapshot.data.documents;
List<Recipe> recipesList = [];
documentSnapshotsList.forEach((documentSnapshot) {
Recipe recipe = Recipe(
id: documentSnapshot["recipe_id"],
name: documentSnapshot["recipe_name"],
image: documentSnapshot["recipe_image_url"],
);
recipesList.add(recipe);
});
return FirestoreListView(recipesList);
} else if (snapshot.hasError)
return Text("Error");
else {
return CircularProgressIndicator();
}
},
),
),
),
);
}