Flutter : Prepare list data from http request - flutter

I am trying to use Flutter Tagging Plugin (https://github.com/sarbagyastha/flutter_tagging). During the testing it is working fine with hard coded list. Now, I am changing it to make call to database and show the list based on that.
Database is returning the data and JSON Parse is also showing the data.
However, I am not able to use that data in Flutter Tagging. As I do not have good knowledge on Flutter.
Here is the code which is working fine when using hard-coded list.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_syntax_view/flutter_syntax_view.dart';
import 'package:flutter_tagging/flutter_tagging.dart';
void main() => runApp(MyApp());
///
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Tagging Demo',
theme: ThemeData(
primarySwatch: Colors.green,
scaffoldBackgroundColor: Colors.white,
),
home: MyHomePage(),
);
}
}
///
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _selectedValuesJson = 'Nothing to show';
List<Language> _selectedLanguages;
#override
void initState() {
_selectedLanguages = [];
super.initState();
}
#override
void dispose() {
_selectedLanguages.clear();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Tagging Demo'),
),
body: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: FlutterTagging<Language>(
initialItems: _selectedLanguages,
textFieldConfiguration: TextFieldConfiguration(
decoration: InputDecoration(
border: InputBorder.none,
filled: true,
fillColor: Colors.green.withAlpha(30),
hintText: 'Search Tags',
labelText: 'Select Tags',
),
),
findSuggestions: LanguageService.getLanguages,
additionCallback: (value) {
return Language(
name: value,
position: 0,
);
},
onAdded: (language) {
// api calls here, triggered when add to tag button is pressed
return Language();
},
configureSuggestion: (lang) {
return SuggestionConfiguration(
title: Text(lang.name),
subtitle: Text(lang.position.toString()),
additionWidget: Chip(
avatar: Icon(
Icons.add_circle,
color: Colors.white,
),
label: Text('Add New Tag'),
labelStyle: TextStyle(
color: Colors.white,
fontSize: 14.0,
fontWeight: FontWeight.w300,
),
backgroundColor: Colors.green,
),
);
},
configureChip: (lang) {
return ChipConfiguration(
label: Text(lang.name),
backgroundColor: Colors.green,
labelStyle: TextStyle(color: Colors.white),
deleteIconColor: Colors.white,
);
},
onChanged: () {
setState(() {
_selectedValuesJson = _selectedLanguages
.map<String>((lang) => '\n${lang.toJson()}')
.toList()
.toString();
_selectedValuesJson =
_selectedValuesJson.replaceFirst('}]', '}\n]');
});
},
),
),
SizedBox(
height: 20.0,
),
Expanded(
child: SyntaxView(
code: _selectedValuesJson,
syntax: Syntax.JAVASCRIPT,
withLinesCount: false,
syntaxTheme: SyntaxTheme.standard(),
),
),
],
),
);
}
}
/// LanguageService
class LanguageService {
/// Mocks fetching language from network API with delay of 500ms.
static Future<List<Language>> getLanguages(String query) async {
await Future.delayed(Duration(milliseconds: 500), null);
return <Language>[
Language(name: 'JavaScript', position: 1),
Language(name: 'Python', position: 2),
Language(name: 'Java', position: 3),
Language(name: 'PHP', position: 4),
Language(name: 'C#', position: 5),
Language(name: 'C++', position: 6),
]
.where((lang) => lang.name.toLowerCase().contains(query.toLowerCase()))
.toList();
}
}
/// Language Class
class Language extends Taggable {
///
final String name;
///
final int position;
/// Creates Language
Language({
this.name,
this.position,
});
#override
List<Object> get props => [name];
/// Converts the class to json string.
String toJson() => ''' {
"name": $name,\n
"position": $position\n
}''';
}
I have create a http request function as below.
class LanguageService {
/// Mocks fetching language from network API with delay of 500ms.
static Future<List<Taggable>> getLanguages(String query) async {
List searchlists = [];
String searchvalue = query;
var dtguid = 10;
var dtgname = 'Test';
int count = 0;
String nodata;
await Future.delayed(Duration(seconds: 1), null);
if(searchvalue.length > 2 && searchvalue.length < 15 ){
searchlists.clear();
try{
var deviceid = '1234';
var dtgUid = '10';
dtguid = dtgUid;
print(searchvalue);
var body = { "uid" : dtgUid, "deviceid": deviceid, "searchtext": searchvalue};
var url = 'http://192.168.100.4:8080/search_tags.php';
// Starting Web API Call.
var response = await http.post(url, body: json.encode(body)).timeout(Duration(seconds: 5),
onTimeout: (){
return null;
});
if(response.statusCode == 200){
final data = getTagsFromJson(response.body);
var totalrec = data.content.length;
print('hi $totalrec');
if(data.content.length > 0 && data.content[0].tagname != 'Empty'){
for (var i in data.content) {
searchlists.add(i);
print(i.tagname);
}
}else{
nodata = 'No Record Found';
}
print(searchlists.length);
}
}catch(e){
print("Exception Caught: $e");
}
return searchlists;
}else{
return null;
}
Here is the JSON Parse File.
GetTags getTagsFromJson(String str) => GetTags.fromJson(json.decode(str));
class GetTags {
List<Content> content;
bool success;
String error;
GetTags({
this.error,
this.content,
this.success,
});
factory GetTags.fromJson(Map<String, dynamic> json) => GetTags(
error: json["error"],
content: (json["content"] as List).map((x) => Content.fromJson(x)).toList(),
success: json["success"],
);
}
class Content {
String tagname;
Content({
this.tagname,
});
factory Content.fromJson(Map<String, dynamic> json) => Content(
tagname: json == null ? 'Empty' : json["tagname"]
);
}

Related

Flutter when clicked button will POST data to API but fail

I create food order app with flutter, but i found some error on my code when i try to create some button which works for POST data to API. I hope you guys can help me, your help is very useful for me, thank you
this is a response from API,
This is an example of the data that can be sent
{
"nominal_diskon": "50000",
"nominal_pesanan": "100000",
"items": [
{ "id": 1, "harga": 10000, "catatan": "Tes" },
{ "id": 2, "harga": 10000, "catatan": "Tes" },
{ "id": 3, "harga": 10000, "catatan": "Tes" }
]}
this is a transaction_service.dart
class TransactionService {
String baseUrl = 'https://tes-mobile.landa.id/api';
Future<bool> checkout(
double diskon, double totalprice, List<MenuModel> menus) async {
var url = '$baseUrl/order';
var body = jsonEncode(
{
'nominal_diskon': diskon,
'nominal_pesanan': totalprice,
'items': menus
.map(
(menu) =>
{'id': menu.id, 'harga': menu.harga, 'catatan': menu.catatan},
)
.toList(),
},
);
var response = await http.post(
Uri.parse(url),
body: body,
);
print(response.body);
if (response.statusCode == 200) {
return true;
} else {
throw Exception('Gagal Melakukan Checkout!');
}
}
}
this is a transaction_provider.dart
class TransactionProvider with ChangeNotifier {
Future<bool> checkout(
double diskon, double totalprice, List<MenuModel> menus) async {
try {
if (await TransactionService().checkout(diskon, totalprice, menus)) {
return true;
} else {
return false;
}
} catch (e) {
print(e);
return false;
}
}
}
this is a home_page.dart which runs the button
class HomePage extends StatefulWidget {
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String voucherCode = "";
#override
Widget build(BuildContext context) {
MenuProvider menuProvider = Provider.of<MenuProvider>(context);
VoucherProvider voucherProvider = Provider.of<VoucherProvider>(context);
TransactionProvider transactionProvider =
Provider.of<TransactionProvider>(context);
double hargaAkhir =
menuProvider.totalPrice() - voucherProvider.diskonHarga();
handleCheckout() async {
if (await transactionProvider.checkout(
10000,
100000,
menuProvider.menus,
)) {
Navigator.pushNamedAndRemoveUntil(
context, '/order-page', (route) => false);
}
}
Widget content() {
return ListView(
padding: EdgeInsets.symmetric(
horizontal: 25,
),
children: menuProvider.menus
.map(
(menu) => MenuCard(menu),
)
.toList(),
);
}
Widget customBottomNav() {
...
child: RaisedButton(
onPressed: handleCheckout,
child: Text('Pesan Sekarang',
style: whiteTextStyle.copyWith(
fontWeight: bold, fontSize: 14)),
color: menuProvider.totalItems() >= 1
? kPrimaryColor
: kDarkGreyColor,
textColor: kWhiteColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
side: BorderSide(
color: menuProvider.totalItems() >= 1
? Color(0xFF00717F)
: kDarkGreyColor,
width: 1,
),
),
),
)
],
),
),
],
),
);
}
return MaterialApp(
home: Scaffold(
backgroundColor: kWhiteColor,
body: content(),
bottomNavigationBar: customBottomNav(),
));
}
}

Flutter Dynamic Searching appBar

I'm trying to create a dynamic search in the appBar, but unfortunately I'm not succeeding and I have an error on this line.
results = _listPlaces.where((places) => places["place"].toLowerCase().contains(enteredKeyword.toLowerCase())
Full code:
import 'package:favspot/src/views/places_card.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import '../../services/places.dart';
import 'dart:async';
class SeachPlaces extends StatefulWidget {
#override
State<SeachPlaces> createState() => _SeachPlacesState();
}
class _SeachPlacesState extends State<SeachPlaces> {
List<Object> _listPlaces = [];
List<Object> _searchSearch = [];
#override
initState(){
_searchSearch = _listPlaces;
super.initState();
}
void _runFilter(String enteredKeyword) {
List<Object> results = [];
if (enteredKeyword.isEmpty) {
results = _listPlaces;
} else {
results = _listPlaces.where((places) => places["place"].toLowerCase().contains(enteredKeyword.toLowerCase())
).toList();
setState((){
_searchSearch = results;
});
}
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
getPlacesList();
}
TextEditingController? _textEditngController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Container(
width: double.infinity,
height: 40,
decoration: BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.circular(30)),
child: Center(
child:TextField(
onChanged: (value) => _runFilter(value),
controller: _textEditngController,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(5),
prefixIcon: Icon(Icons.search),
suffix: IconButton(
icon: Icon(Icons.clear),
onPressed: null,
),
hintText: 'Searching...',
border: InputBorder.none,
),
),
),
),
),
body: SafeArea(
child: ListView.builder(
itemCount: _searchSearch.length,
itemBuilder: (context, index) {
return PlacesCard(_searchSearch[index] as Places);
},
)
),
);
}
Future getPlacesList() async {
var data = await FirebaseFirestore.instance
.collection('places')
.orderBy('city', descending: false)
.get();
setState(() {
_listPlaces = List.from(data.docs.map((doc) => Places.fromSnapshot(doc)));
});
}
}
Here is de class Places
class Places {
String? place;
String? city;
String? status;
Places();
Map<String, dynamic> toJson() => {
'city' : city,
'status' : status,
};
Places.fromSnapshot(snapshot) :
place = snapshot.id,
city = snapshot.data()['city'],
status = snapshot.data()['status'];
}
Consider to use List<Places> _listPlaces instead of List<Object> _listPlaces, so you can access properties like this:
results = _listPlaces.where((places) => places.place != null && places.place!.toLowerCase().contains(enteredKeyword.toLowerCase())
).toList();

The argument type 'void Function(Map<String, bool>)' can't be assigned to the parameter type 'Map<String, bool>'

I'm trying to send the filter to the filter screen but getting an error.
The argument type 'void Function(Map<String, bool>)' can't be assigned to the parameter type 'Map<String, bool>'.
Main screen code
import 'package:flutter/material.dart';
import 'package:meal_app/dummy.dart';
import 'package:meal_app/screens/bottom_navigation.dart';
import 'package:meal_app/screens/catagory_item_screen.dart';
import 'package:meal_app/screens/categorise_screen.dart';
import 'package:meal_app/screens/filters_screen.dart';
import 'package:meal_app/screens/homescreen.dart';
import 'package:meal_app/screens/meal_item_details.dart';
import 'package:meal_app/widgets/meal.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
// This widget is the root of your application.
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Map<String, bool> _filter = {
'gluton': false,
'lactose': false,
"vrgan": false,
"vegetarian": false
};
List<Meal> _availablemeal = DUMMY_MEALS;
void _applyfilter(Map<String, bool> filterData) {
setState(() {
_filter = filterData;
_availablemeal = DUMMY_MEALS.where((meals) {
if (_filter['gluton']! && !meals.isGlutenFree) {}
if (_filter['lactose']! && !meals.isLactoseFree) {
return false;
}
if (_filter['vrgan']! && !meals.isVegan) {
return false;
}
if (_filter['vegetarian']! && !meals.isVegetarian) {
return false;
}
return true;
}).toList();
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Meal App',
theme: ThemeData(
primarySwatch: Colors.pink,
accentColor: Colors.amber,
canvasColor: Color.fromRGBO(255, 255, 255, 1),
fontFamily: 'Raleway',
textTheme: ThemeData.light().textTheme.copyWith(
bodyText1: TextStyle(
color: Color.fromRGBO(20, 50, 51, 1),
),
bodyText2: TextStyle(color: Color.fromRGBO(20, 50, 51, 1)),
subtitle1: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
fontFamily: "RobotoCondensed"),
),
),
initialRoute: '/',
routes: {
'/': (ctx) => BottomNavigation(),
CatagoryItemScreen.routes: (ctx) => CatagoryItemScreen(_availablemeal),
MealDetails.routs: (ctx) => MealDetails(),
FiltersScreen.routeName: (ctx) => FiltersScreen(_filter, _applyfilter),
},
);
}
}
When i was using final VoidCallBack it was placing no error in main.dart but giving error in onPressed:widget.applyfilter(selectedfilter); then i replaced VoidCallBack with Function(Map) then it start giving error in main.dart code.
Filter screen
import 'package:flutter/material.dart';
import 'package:meal_app/widgets/drawer.dart';
class FiltersScreen extends StatefulWidget {
final Function(Map) applyfilter;
final Map<String, bool> currentfilter;
FiltersScreen(this.applyfilter, this.currentfilter);
static const routeName = '/filter';
#override
State<FiltersScreen> createState() => _FiltersScreenState();
}
class _FiltersScreenState extends State<FiltersScreen> {
Widget _buildSwitchTile(String title, String subTitle, var currentVal,
Function(bool) nextQuestion) {
return SwitchListTile(
title: Text(title),
subtitle: Text(subTitle),
value: currentVal,
activeColor: Colors.redAccent,
onChanged: nextQuestion,
);
}
var isGlutenFree = false;
var isLactoseFree = false;
var isVegan = false;
var isVegetarian = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Filter Screen"),
actions: [
IconButton(
icon: Icon(Icons.save),
onPressed: () {
final selectedfilter = {
'gluton': isGlutenFree,
'lactose': isLactoseFree,
"vrgan": isVegan,
"vegetarian": isVegetarian
};
widget.applyfilter(selectedfilter);
})
],
),
drawer: MainDrawer(),
body: Column(children: [
Container(
margin: EdgeInsets.all(20),
child: Text(
"Adjust your filters here",
style: TextStyle(fontWeight: FontWeight.w900, fontSize: 26),
),
),
Expanded(
child: ListView(
children: [
_buildSwitchTile(
"Glutan-Free", "only include Glutan-Free meal", isGlutenFree,
(newValue) {
setState(() {
isGlutenFree = newValue;
});
}),
_buildSwitchTile(
"Lactose-Free", "only include Lactose-Free meal", isLactoseFree,
(newValue) {
setState(() {
isLactoseFree = newValue;
});
}),
_buildSwitchTile(
"Vegan-Free", "only include Vegan-Free meal", isVegan,
(newValue) {
setState(() {
isVegan = newValue;
});
}),
_buildSwitchTile("Vegetarian-Free",
"only include Vegetarian-Free meal", isVegetarian, (newValue) {
setState(() {
isVegetarian = newValue;
});
}),
],
))
]),
);
}
}
You pass the arguments in the wrong order. Switch them:
FiltersScreen.routeName: (ctx) => FiltersScreen(_applyfilter, _filter)
Also define a matching map type in your Filter screen:
final Function(Map<String, bool>) applyfilter;
(Otherwise you would get another error message after fixing the order of your arguments)

Is it possible to send a query type url to Future in Flutter?

I need to shape myUrl inside Future related to username which I got from myfirstpage, I can get the name and use it in my homepage title but I couldn't figured out how can I use it in myUrl(instead of "$_name"),
Probably I made a mistake with point to data with "pushNamed(MyHomePage.routeName);" actually I don't need that value in MyHomePage, I just need it for shape myUrl line, also I tried to make "_name" value as a global value etc just not couldn't succeed..
import 'package:flutter/cupertino.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
import 'dart:convert';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
new GlobalKey<RefreshIndicatorState>();
Future<bool> saveNamedPreference(String name) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString("name", name);
return prefs.commit();
}
Future<String> getNamePreferences() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String name = prefs.getString("name");
return name;
}
Payload payloadFromJson(String str) {
return Payload.fromJson(json.decode(str));
}
String payloadToJson(Payload data) {
return json.encode(data.toJson());
}
Future<Payload> getData() async{
String myUrl = 'http://lunedor.pythonanywhere.com/query?username=$_name';
http.Response response = await http.get(myUrl);
print(myUrl);
return response == null ? getData() : payloadFromJson(response.body);
}
class Payload {
String moviecast;
String moviedirectors;
String moviegenre;
String movieposterurl;
String movierating;
String movieruntime;
String moviesummary;
String movietitle;
String moviewriters;
String movieyear;
Payload({
this.moviecast,
this.moviedirectors,
this.moviegenre,
this.movieposterurl,
this.movierating,
this.movieruntime,
this.moviesummary,
this.movietitle,
this.moviewriters,
this.movieyear,
});
factory Payload.fromJson(Map<String, dynamic> json) => Payload(
moviecast: json["Actors"],
moviedirectors: json["Director"],
moviegenre: json["Genre"],
movieposterurl: json["Poster"],
movierating: json["imdbRating"],
movieruntime: json["Runtime"],
moviesummary: json["Plot"],
movietitle: json["Title"],
moviewriters: json["Writer"],
movieyear: json["Year"],
);
Map<String, dynamic> toJson() => {
"moviecast": moviecast,
"moviedirectors": moviedirectors,
"moviegenre": moviegenre,
"movieposterurl": movieposterurl.replaceAll('300.jpg', '900.jpg'),
"movierating": movierating,
"movieruntime": movieruntime,
"moviesummary": moviesummary,
"movietitle": movietitle,
"moviewriters": moviewriters,
"movieyear": movieyear,
};
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Random Movie',
theme: new ThemeData(
primarySwatch: Colors.grey,
),
home: new MyFirstPage(),
routes: <String, WidgetBuilder>{
MyHomePage.routeName: (context) => new MyHomePage(),
},
);
}
}
class MyFirstPage extends StatefulWidget {
#override
_MyFirstPageState createState() => new _MyFirstPageState();
}
class _MyFirstPageState extends State<MyFirstPage>{
var _controller = new TextEditingController();
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
backgroundColor: Colors.blueGrey,
centerTitle: true,
title: new Text("Please enter your Trakt username",
style: new TextStyle(
fontSize: 18.0,
color: Colors.white,
),
),
),
body: new ListView(
children: <Widget>[
new ListTile(
title: new TextField(
controller: _controller,
),
),
new ListTile(
title: new RaisedButton(
child: new Text("Submit"),
onPressed:(){setState(() {
saveName();
});
}),
)
],
),
);
}
void saveName() {
String name = _controller.text;
saveNamedPreference(name).then((bool committed) {
Navigator.of(context).pushNamed(MyHomePage.routeName);
});
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
static String routeName = "/myHomePage";
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
Payload payload;
class _MyHomePageState extends State<MyHomePage> {
Modal modal = Modal();
bool isLoading = true;
String _name = "";
#override
void initState() {
// TODO: implement initState
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {loadData();
WidgetsBinding.instance.addPostFrameCallback((_) => _refreshIndicatorKey.currentState.show());
getNamePreferences().then(updateName);
});
}
void loadData() async {
payload = await getData();
isLoading = false;
setState(() {});
print('${payload.movieposterurl.replaceAll('300.jpg', '900.jpg')}');
}
void updateName(String name) {
setState(() {
this._name = name;
ValueKey(_name);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar:
AppBar(
backgroundColor: Colors.blueGrey,
title:
isLoading ? Center(child: CircularProgressIndicator()):Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Center(
child: Text('${payload.movietitle}', maxLines: 2, textAlign: TextAlign.center,
style: new TextStyle(
fontSize: 18.0,
color: Colors.white,
),
),
),
Text('${payload.movieyear}' + " - " + _name + " - " + '${payload.movierating}',
style: new TextStyle(
fontSize: 14.0,
color: Colors.black,
fontStyle: FontStyle.italic,),
),
]
),
),
),
body:
isLoading ? Center(child: CircularProgressIndicator()):
RefreshIndicator(
key: _refreshIndicatorKey,
onRefresh: () async{payload = await getData();
isLoading = false;
setState(() {});
},
child: Center(
child:ListView(
shrinkWrap: true,
children: [
FittedBox(
alignment: Alignment.center,
child:
Image.network('${payload.movieposterurl.replaceAll('300.jpg', '900.jpg')}'),
),
]
)
)
),
bottomNavigationBar: isLoading ? Center(child: CircularProgressIndicator()):
BottomAppBar(
child: Container(
color: Colors.grey,
child: SizedBox(
width: double.infinity,
child:
FlatButton(
color: Colors.grey,
textColor: Colors.black,
onPressed: () {
modal.mainBottomSheet(context);
},
child: Text("Details",
style: TextStyle(fontSize: 16.0),),
),
),
),
),
);
}
}
class Modal {
mainBottomSheet(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
_createTile(
context, "Genre: " + payload.moviegenre + "\n" + "Runtime: " + payload.movieruntime, Icons.local_movies,
_action),
_createTile(
context, "Director: " + payload.moviedirectors,
Icons.movie_creation,
_action),
_createTile(
context, "Writer: " + payload.moviewriters,
Icons.movie,
_action),
_createTile(
context, "Cast: " + payload.moviecast, Icons.chrome_reader_mode,
_action),
_createTile(
context, "Summary: " + payload.moviesummary, Icons.recent_actors, _action),
],
),
);
}
);
}
ListTile _createTile(BuildContext context, String name, IconData icon,
Function action) {
return ListTile(
leading: Icon(icon),
title: Text(name),
onTap: () {
Navigator.pop(context);
action();
},
);
}
_action() {
print('action');
}
}
Not completely sure I got your question, but it should be enough to modify your getData() method to accept a String in parameters, at the moment getData() is a top-level function that doesn't know the _name value because is a private instance variable of _MyHomePageState
Future<Payload> getData(String name) async{
String myUrl = 'http://lunedor.pythonanywhere.com/query?username=$name';
http.Response response = await http.get(myUrl);
print(myUrl);
return response == null ? getData() : payloadFromJson(response.body);
}
And then in your loadData() method pass the correct value
void loadData() async {
payload = await getData(_name);
isLoading = false;
setState(() {});
print('${payload.movieposterurl.replaceAll('300.jpg', '900.jpg')}');
}
One last thing, you should add the "reload" logic when you change the name
void updateName(String name) {
setState(() {
isLoading = true;
this._name = name;
ValueKey(_name);
loadData();
});
}
Personally I think that the Payload variable should stay inside your _MyHomePageState class

retrieve body of json from api

I'm trying to return the quote section from this api located here: https://api.quotable.io/random
The json looks like this:
{"_id":"9hIehvX23pvr","content":"There is no charm equal to tenderness
of heart.","author":"Jane Austen"}
Here is the part of the code that connects to the API.
Future<String> _getQuote() async {
final res = await http.get('https://api.quotable.io/random');
return json.decode(res.body);
}
Whenever I run the app, I get this error that tells me it's getting a null. But I know the api works.
_FutureBuilderState#b8df9): I/flutter ( 5315): A non-null String must be provided to a Text widget. I/flutter ( 5315):
'package:flutter/src/widgets/text.dart': I/flutter ( 5315): Failed
assertion: line 269 pos 10: 'data != null'
I just need the "content" part of the json. How would I parse just that part?
Thanks!
#SkyeBoniwell, not getting any response with the api. Sure it's working?
Screenshot:
You can copy paste run full code below
Step1 : add <uses-permission android:name="android.permission.INTERNET"/> to AndroidManifest
Step2 : Use the following class to parse
Demo demoFromJson(String str) => Demo.fromJson(json.decode(str));
String demoToJson(Demo data) => json.encode(data.toJson());
class Demo {
String id;
String content;
String author;
Demo({
this.id,
this.content,
this.author,
});
factory Demo.fromJson(Map<String, dynamic> json) => Demo(
id: json["_id"],
content: json["content"],
author: json["author"],
);
Map<String, dynamic> toJson() => {
"_id": id,
"content": content,
"author": author,
};
}
working demo
full working code
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
Demo demoFromJson(String str) => Demo.fromJson(json.decode(str));
String demoToJson(Demo data) => json.encode(data.toJson());
class Demo {
String id;
String content;
String author;
Demo({
this.id,
this.content,
this.author,
});
factory Demo.fromJson(Map<String, dynamic> json) => Demo(
id: json["_id"],
content: json["content"],
author: json["author"],
);
Map<String, dynamic> toJson() => {
"_id": id,
"content": content,
"author": author,
};
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: FutureBuilderWidget(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
String url = ' http://api.quotable.io/random';
///Method for GET Request
Future<Demo> getDemoResponse() async {
final response = await http.get('https://api.quotable.io/random');
print('response ${response}');
if (response.statusCode == 200) {
print('response body${response.body}');
return demoFromJson(response.body);
} else {
throw Exception('Failed to load ');
}
}
class FutureBuilderWidget extends StatefulWidget {
#override
_FutureBuilderWidgetState createState() => _FutureBuilderWidgetState();
}
class _FutureBuilderWidgetState extends State<FutureBuilderWidget> {
bool _isButtonClicked = false;
var _buttonIcon = Icons.cloud_download;
var _buttonText = "Fetch Data";
var _buttonColor = Colors.green;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Container(
child: Center(
child: Text(
'Future Builder Widget',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
//fontFamily: Utils.ubuntuRegularFont
),
),
),
margin: EdgeInsets.only(right: 48),
),
),
body: Center(
child: FutureBuilder<Demo>(
///If future is null then API will not be called as soon as the screen
///loads. This can be used to make this Future Builder dependent
///on a button click.
future: _isButtonClicked ? getDemoResponse() : null,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
///when the future is null
case ConnectionState.none:
return Text(
'Press the button to fetch data',
textAlign: TextAlign.center,
);
case ConnectionState.active:
///when data is being fetched
case ConnectionState.waiting:
return CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue));
case ConnectionState.done:
///task is complete with an error (eg. When you
///are offline)
if (snapshot.hasError)
return Text(
'Error:\n\n${snapshot.error}',
textAlign: TextAlign.center,
);
///task is complete with some data
return Text(
'Fetched Data:\n\n${snapshot.data.content}',
textAlign: TextAlign.center,
);
}
},
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: FloatingActionButton.extended(
backgroundColor: _buttonColor,
onPressed: () {
///Calling method to fetch data from the server
//getDemoResponse();
///You need to reset UI by calling setState.
setState(() {
_isButtonClicked == false
? _isButtonClicked = true
: _isButtonClicked = false;
if (!_isButtonClicked) {
_buttonIcon = Icons.cloud_download;
_buttonColor = Colors.green;
_buttonText = "Fetch Data";
} else {
_buttonIcon = Icons.replay;
_buttonColor = Colors.deepOrange;
_buttonText = "Reset";
}
});
},
icon: Icon(
_buttonIcon,
color: Colors.white,
),
label: Text(
_buttonText,
style: TextStyle(color: Colors.white),
),
),
);
}
}