Flutter Navigator.pop won't send data back - android-studio

This is my code so far. I dont know whats wrong, I tried a lots of youtube turolial and other things as well, but its looks like the pop wont give back the correct data. I really need help, i spend 2 days already
void main() {
List<String> names = [];
List<String> mgs = [];
runApp(MaterialApp(
title: 'Returning Data',
home: HomeScreen(names, mgs),
));
}
class HomeScreen extends StatelessWidget {
List<String> names = [];
List<String> mgs = [];
HomeScreen(this.names, this.mgs);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
title: Text("Project_Drink"),
),
body: Container(
child: Column(
children: <Widget>[
new Expanded(
child: ListView.builder
(
itemCount: mgs.length,
itemBuilder: (context, Index) {
return Text("Name: " + names[Index]
+" "+ "Mg: " + mgs[Index]);
}
)
)
],
),
),
bottomNavigationBar :BottomAppBar (
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
const Expanded(child: Text("TOTAL : 200")),
FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AddProduct()),
);
},
child: Icon(Icons.add),
),
],
),
),
),
);
}
}
This is the AddProduct i want this to send back the data and then i should be able to put in into a list.Lika a not pad
class AddProduct extends StatefulWidget {
#override
State createState() => new _AddProductState();
}
class _AddProductState extends State<AddProduct> {
List<String> names = [];
List<String> mgs = [];
//final TextEditingController eCtrl = new TextEditingController();
final nameController = TextEditingController();
final mgController = TextEditingController();
#override
Widget build (BuildContext ctxt) {
return new Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
title: Text("New Drink"),
),
body: new Column(
children: <Widget>[
new TextField(
decoration: InputDecoration(
hintText: "Name",
),
controller: nameController,
),
new TextField(
decoration: InputDecoration(
hintText: "Mg",
suffixText: "Mg",
),
controller: mgController,
),
RaisedButton(
onPressed: (){
names.add(nameController.text);
mgs.add(mgController.text);
setState(() {});
nameController.clear();
mgController.clear();
Navigator.pop(context, names + mgs);
},
child: Text("ADD"),
),
],
)
);
}
}

I moved your lists to HomeScreen widget instead of main function. Your main function should just run the app
void main() {
runApp(
MaterialApp(
title: 'Returning Data',
home: HomeScreen(),
),
);
}
And I convert your HomeScreen widget to StatefulWidget insted of StatelessWidget because when you add new items and display it screen your state will change and StatelessWidget is not able to do that. It will be something like that
Navigator.push returns a future value so if you want to declare a variable with the data comes from that, you need to await for it. After you get the data you can add them into your lists but it needs to be inside setState function to update UI
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
List<String> names = [];
List<String> mgs = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
title: Text("Project_Drink"),
),
body: Container(
child: Column(
children: <Widget>[
new Expanded(
child: ListView.builder(
itemCount: mgs.length,
itemBuilder: (context, index) {
return Text("Name: " + names[index] + " " + "Mg: " + mgs[index]);
}
),
),
],
),
),
bottomNavigationBar: BottomAppBar(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Expanded(child: Text("TOTAL : 200")),
FloatingActionButton(
onPressed: () async {
// Navigator.push returns a future value so you need to await for it
var data = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => AddProduct()),
);
// After you get the data from the other page you need to add them into your lists inside setState function to update UI
setState(() {
names.add(data[0]);
mgs.add(data[1]);
});
},
child: Icon(Icons.add),
),
],
),
),
),
);
}
}
I didn't change anything in your AddProduct widget.
class AddProduct extends StatefulWidget {
#override
State createState() => new _AddProductState();
}
class _AddProductState extends State<AddProduct> {
List<String> names = [];
List<String> mgs = [];
//final TextEditingController eCtrl = new TextEditingController();
final nameController = TextEditingController();
final mgController = TextEditingController();
#override
Widget build (BuildContext ctxt) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
title: Text("New Drink"),
),
body: Column(
children: <Widget>[
TextField(
decoration: InputDecoration(
hintText: "Name",
),
controller: nameController,
),
TextField(
decoration: InputDecoration(
hintText: "Mg",
suffixText: "Mg",
),
controller: mgController,
),
RaisedButton(
onPressed: (){
names.add(nameController.text);
mgs.add(mgController.text);
setState(() {});
nameController.clear();
mgController.clear();
Navigator.pop(context, names + mgs);
},
child: Text("ADD"),
),
],
)
);
}
}
Although this code should work as you want, I would suggest you to have a look at some State Management methods such as Provider, Bloc and etc. It will be more effective to create what you want to do.

try this one with simple way , when press then call this method
goToView() async {
bool data=await Navigator.push(context, new CupertinoPageRoute(builder: (BuildContext context) {
return new CoolForgot();
}));
print(data);
}
My Next View is Forgot Screen so i have used CoolForgot(), you can use as per your requirement.
then when press on back button in Next View(In my case CoolForgot()) called this
Navigator.pop(context,true);
I have pass bool value and get bool value , you can pass any type of object and get from it.

Related

Reducing the number of considered missed Gc histogram windows from 101 to 100

I am attempting to build a weather app as part of a Flutter course I am taking, and a message stating:
Reducing the number of considered missed Gc histogram windows from 101 to 100
appears in my console, when I would expect weather data instead. Is anyone familiar with this message?
I am pasting the code from the screens involved below, for reference.
location_screen.dart
import 'package:flutter/material.dart';
import 'package:clima/utilities/constants.dart';
class LocationScreen extends StatefulWidget {
LocationScreen({this.locationWeather});
final locationWeather;
#override
_LocationScreenState createState() => _LocationScreenState();
}
class _LocationScreenState extends State<LocationScreen> {
#override
void initState() {
super.initState();
print(widget.locationWeather);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('images/location_background.jpg'),
fit: BoxFit.cover,
colorFilter: ColorFilter.mode(
Colors.white.withOpacity(0.8), BlendMode.dstATop),
),
),
constraints: BoxConstraints.expand(),
child: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
FlatButton(
onPressed: () {},
child: Icon(
Icons.near_me,
size: 50.0,
),
),
FlatButton(
onPressed: () {},
child: Icon(
Icons.location_city,
size: 50.0,
),
),
],
),
Padding(
padding: EdgeInsets.only(left: 15.0),
child: Row(
children: <Widget>[
Text(
'32°',
style: kTempTextStyle,
),
Text(
'☀️',
style: kConditionTextStyle,
),
],
),
),
Padding(
padding: EdgeInsets.only(right: 15.0),
child: Text(
"It's 🍦 time in San Francisco!",
textAlign: TextAlign.right,
style: kMessageTextStyle,
),
),
],
),
),
),
);
}
}
/*
double temperature = decodedData['main']['temp'];
int condition = decodedData['weather'][0]['id'];
String cityName = decodedData['name'];
*/
loading_screen.dart
import 'package:clima/screens/location_screen.dart';
import 'package:clima/services/networking.dart';
import 'package:flutter/material.dart';
import 'package:clima/services/location.dart';
import 'package:clima/services/networking.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'location_screen.dart';
const apiKey = 'APIKEY';
class LoadingScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _LoadingScreenState();
}
}
class _LoadingScreenState extends State<LoadingScreen> {
double latitude;
double longitude;
#override
void initState() {
super.initState();
getLocation();
}
void getLocationData() async {
Location location = Location();
await location.getCurrentLocation();
latitude = location.latitude;
longitude = location.longitude;
NetworkHelper networkHelper = NetworkHelper(
'https://api.openweathermap.org/data/2.5/weather?lat=$latitude&lon=$longitude&appid=$apiKey');
var weatherData = await networkHelper.getData();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LocationScreen(
locationWeather: weatherData,
);
},
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: SpinKitDoubleBounce(
color: Colors.white,
size: 100.0,
),
),
);
}
}
networking.dart
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 jsonDecode(data);
} else {
print(response.statusCode);
}
}
}
You should disconnect your app. Delete it from the device or emulator if you're using one, then cold restart your app again. It will work just fine.
It worked for me on my device.

How can I make the switches, which have their own StatelessWidget Class toggle when clicked?

I am trying to make two switches toggle between on and off when they are clicked. I created a StatelessWidget class for the design of the switches. However, when I use this, and call the class in my User interface class, the switches do not change state. How can I update my code to allow for there to be a change?
import 'package:flutter/material.dart';
class NotificationItem extends StatelessWidget {
NotificationItem(
{#required this.title,
#required this.pushStatus,
#required this.emailStatus});
String title;
bool pushStatus;
bool emailStatus;
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(
child: Padding(
padding: EdgeInsets.all(20),
child: Text(
title,
style: TextStyle(
fontFamily: kFontFamilyNormal,
fontSize: 17,
color: AppColor.text,
fontWeight: FontWeight.w500),
),
),
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Switch(
value: emailStatus,
onChanged: (value) {
emailStatus = value;
print(emailStatus);
},
activeTrackColor: AppColor.primaryColorDark,
activeColor: AppColor.white,
),
Switch(
value: pushStatus,
onChanged: (value) {
pushStatus = value;
print(pushStatus);
},
activeTrackColor: AppColor.primaryColorDark,
activeColor: AppColor.white,
),
],
),
),
],
);
}
}
and the following code is how I am calling it:
NotificationItem(
title: 'New messages',
emailStatus: emailStatus,
pushStatus: pushStatus,
)
Since you are changing state, it has to be a StatefulWidget. Like so:
class NotificationItem extends StatefulWidget {
const NotificationItem({
Key key,
#required this.title,
#required this.pushStatus,
#required this.emailStatus,
});
final String title;
final bool pushStatus;
final bool emailStatus;
#override
_NotificationItemState createState() => _NotificationItemState();
}
class _NotificationItemState extends State<NotificationItem> {
String _title;
bool _pushStatus;
bool _emailStatus;
void initState() {
super.initState();
_title = widget.title;
_pushStatus = widget.pushStatus;
_emailStatus = widget.emailStatus;
}
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
_title,
),
),
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Switch(
value: _emailStatus,
onChanged: (value) {
setState(() => _emailStatus = value);
print(_emailStatus);
},
),
Switch(
value: _pushStatus,
onChanged: (value) {
setState(() => _pushStatus = value);
print(_pushStatus);
},
),
],
),
),
],
);
}
}
In order to change UI state you have to use StatefulWidget
You can either convert NotificationItem into a StatefulWidget or extract each switch into its own StatefulWidget
Or I recommend you to have a look at MVVM pattern using Get libary or Stacked
Your code with Get would look like this:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class NotificationItemViewModel extends GetxController {
bool pushStatus = false;
bool emailStatus = false;
void changeEmailStatus(bool newValue) {
emailStatus = newValue;
print(emailStatus);
update();
}
void changePushStatus(bool newValue) {
pushStatus = newValue;
print(pushStatus);
update();
}
}
class NotificationItem extends StatelessWidget {
const NotificationItem({#required this.title});
final String title;
#override
Widget build(BuildContext context) {
return GetBuilder<NotificationItemViewModel>(
init: NotificationItemViewModel(),
builder: (model) {
return Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(20),
child: Text(
title,
style: TextStyle(
fontFamily: kFontFamilyNormal,
fontSize: 17,
color: AppColor.text,
fontWeight: FontWeight.w500,
),
),
),
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Switch(
value: model.emailStatus,
onChanged: model.changeEmailStatus,
activeTrackColor: AppColor.primaryColorDark,
activeColor: AppColor.white,
),
Switch(
value: model.pushStatus,
onChanged: model.changePushStatus,
activeTrackColor: AppColor.primaryColorDark,
activeColor: AppColor.white,
),
],
),
),
],
);
},
);
}
}

How can I implement search in this Flutter app

I'm trying to add a search feature to this flutter app since the json file it pulls data from has 7000 results.
Mainly I'm trying to do search for "ctry" and "peopnameincountry". This was ripped from https://www.youtube.com/watch?v=EwHMSxSWIvQ
As is .. it works fine in fetching the json list and the tap to show detail page works as well.
I just need to implement the search on the main page so I don't have to scroll through the thousands of results.
Appreciate any help .. thank you all.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() => runApp(new UnReached());
class UnReached extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Unreached'),
);
}
}
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> {
Future<List<User>> _getUsers() async {
var data = await http.get("https://cmfiflutterapp.s3-ap-southeast-2.amazonaws.com/UnreachedPeoplesGroup.json");
var jsonData = json.decode(data.body);
List<User> users = [];
for(var u in jsonData){
User user = User(u["ctry"], u["peopnameincountry"], u["population"], u["primarylanguagename"], u["biblestatus"], u["primaryreligion"], u["continent"]);
users.add(user);
}
print(users.length);
return users;
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: Text(widget.title),
),
body: Container(
child: FutureBuilder(
future: _getUsers(),
builder: (BuildContext context, AsyncSnapshot snapshot){
print(snapshot.data);
if(snapshot.data == null){
return Container(
child: Center(
child: Text("Loading...")
)
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: Icon(Icons.arrow_forward_ios),
// leading: CircleAvatar(
// backgroundImage: NetworkImage(
// snapshot.data[index].picture
// ),
// ),
title: Text(snapshot.data[index].peopnameincountry),
subtitle: Text(snapshot.data[index].ctry),
onTap: (){
Navigator.push(context,
new MaterialPageRoute(builder: (context) => DetailPage(snapshot.data[index]))
);
},
);
},
);
}
},
),
),
);
}
}
Try adding these function in your code:
import 'package:flutter/material.dart';
import 'dart:core';
class HomeScreen1 extends StatefulWidget {
#override
HomeScreenState createState() => HomeScreenState();
}
class HomeScreenState extends State<HomeScreen1> {
var searchController = new TextEditingController();
String search;
List<String> _filterList;
String _query = "";
bool _firstSearch = true;
#override
void initState() {
super.initState();
}
HomeScreenState() {
searchController.addListener(() {
if (searchController.text.isEmpty) {
setState(() {
_firstSearch = true;
_query = "";
});
} else {
setState(() {
_firstSearch = false;
_query = searchController.text;
});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: new Container(
margin: EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0),
child: new Column(
children: <Widget>[
_createSearchView(),
new Expanded(
child: _firstSearch ? _createListView() : _performSearch(),
),
],
),
),
);
}
Widget _createSearchView() {
return new Container(
decoration: BoxDecoration(border: Border.all(width: 1.0)),
child: new TextField(
controller: searchController,
decoration: InputDecoration(
icon: Icon(Icons.search),
hintText: "Search",
hintStyle: new TextStyle(color: Colors.grey[300]),
),
//textAlign: TextAlign.center,
),
);
}
Widget _createListView() {
return FutureBuilder(
future: _getUsers(),
builder: (BuildContext context, AsyncSnapshot snapshot){
print(snapshot.data);
if(snapshot.data == null){
return Container(
child: Center(
child: Text("Loading...")
)
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: Icon(Icons.arrow_forward_ios),
// leading: CircleAvatar(
// backgroundImage: NetworkImage(
// snapshot.data[index].picture
// ),
// ),
title: Text(snapshot.data[index].peopnameincountry),
subtitle: Text(snapshot.data[index].ctry),
onTap: (){
Navigator.push(context,
new MaterialPageRoute(builder: (context) => DetailPage(snapshot.data[index]))
);
},
);
},
);
}
},
),
}
Widget _performSearch() {
return FutureBuilder<List>(builder: (context, snapshot) {
_filterList = new List<String>();
for (int i = 0; i < snapshot.data.length; i++) {
var item = snapshot.data[i];
if ((item.toString().toLowerCase()).contains(_query.toLowerCase())) {
_filterList.add(item.toString());
}
}
return _createFilteredListView();
});
}
Widget _createFilteredListView() {
return ListView.builder(
itemCount: _filterList.length,
itemBuilder: (BuildContext context, int index) {
return new Card(
color: Colors.white,
elevation: 5.0,
child: new Container(
margin: EdgeInsets.all(15.0),
child: new Text("${_filterList[index]}"),
),
);
});
}
}
The concept of a FutureBuilder widget is to be build as soon as it is received, but meanwhile, the snapshot contains no data at all. So when you're calling :
for (int i = 0; i < snapshot.data.length; i++) {
you're, at least at first, calling length on null since the data is not yet received.
The solution is to create a switch and call `snapshot.data when the status is completed:
switch (snapshot.connectionState) {
case ConnectionState.none:
return DefaultWidget(); // For instance a CircularProgress
case ConnectionState.active:
return DefaultWidget(); // For instance a CircularProgress
case ConnectionState.waiting:
return DefaultWidget(); // For instance a CircularProgress
case ConnectionState.done:
if (snapshot.hasError)
return ErrorWidget('Error: ${snapshot.error}'); //For example a Text Widget
// Your code here:
_filterList = new List<String>();
for (int i = 0; i < snapshot.data.length; i++) {
var item = snapshot.data[i];
if ((item.toString().toLowerCase()).contains(_query.toLowerCase())) {
_filterList.add(item.toString());
}
}
return _createFilteredListView();
}
return null; // unreachable
More on this here
My apologies guys...I ended up taking a slightly different approach which I thought was slightly faster in response than the FutureBuilder approach. Maybe it's just my internet. Not sure.
import 'package:flutter/material.dart';
import 'dart:core';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
import 'package:progress_indicators/progress_indicators.dart';
class IslandWaves extends StatefulWidget {
#override
HomeScreenState createState() => HomeScreenState();
}
class HomeScreenState extends State<IslandWaves> {
List<User> _list = [];
List<User> _search = [];
var loading = false;
Future<Null> fetchData() async {
setState(() {
loading = true;
});
_list.clear();
final response = await http.get(
"https://cmfiflutterapp.s3-ap-southeast-2.amazonaws.com/UnreachedPeoplesGroup.json");
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
setState(() {
for (Map i in data) {
_list.add(User.formJson(i));
loading = false;
}
});
}
}
TextEditingController controller = new TextEditingController();
onSearch(String text) async {
_search.clear();
if (text.isEmpty) {
setState(() {});
return;
}
_list.forEach((f) {
if (f.ctry.contains(text) ||
f.peopnameincountry.toString().contains(text)) _search.add(f);
});
setState(() {});
}
#override
void initState() {
// TODO: implement initState
super.initState();
fetchData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(10.0),
color: Colors.blue,
child: Card(
child: ListTile(
leading: Icon(Icons.search),
title: TextField(
controller: controller,
onChanged: onSearch,
decoration: InputDecoration(
hintText: "Search", border: InputBorder.none),
),
trailing: IconButton(
onPressed: () {
controller.clear();
onSearch('');
},
icon: Icon(Icons.cancel),
),
),
),
),
loading
? Center(
heightFactor: 20.0,
child: FadingText('Loading...'),
)
: Expanded(
child: _search.length != 0 || controller.text.isNotEmpty
? ListView.builder(
itemCount: _search.length,
itemBuilder: (context, i) {
final b = _search[i];
return GestureDetector(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) =>
DetailPage(_search[i])));
debugPrint('TopNav');
},
child: Container(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
b.ctry,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0),
),
SizedBox(
height: 4.0,
),
Text(b.peopnameincountry),
],
)),
);
},
)
: ListView.builder(
itemCount: _list.length,
itemBuilder: (context, i) {
final a = _list[i];
return GestureDetector(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) =>
DetailPage(_list[i])));
debugPrint('BottomNav');
},
child: Container(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
a.ctry,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0),
),
SizedBox(
height: 4.0,
),
Text(a.peopnameincountry),
],
)
),
);
},
),
),
],
),
),
);
}
}
class DetailPage extends StatelessWidget{....etc.}

Flutter, text to top

I've started playing with Flutter a little bit.
I created a page, that looks like this:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:smooth_star_rating/smooth_star_rating.dart';
import 'package:intl/intl.dart';
class LandOffer extends StatefulWidget {
final String startPoint;
final String endPoint;
const LandOffer({Key key, this.startPoint, this.endPoint}) : super(key: key);
#override
State<StatefulWidget> createState() {
return _LandOffer(startPoint: this.startPoint, endPoint: this.endPoint);
}
}
class _LandOffer extends State<LandOffer> {
final String startPoint;
final String endPoint;
var _json;
String _name;
String _lastName;
String _image;
var isLoading = false;
_fetchBackendData() async {
setState(() {
isLoading = true;
print('Beginning loading');
});
final response =
await http.get("https://randomuser.me/api/?inc=name,picture");
if (response.statusCode == 200) {
_json = json.decode(response.body);
setState(() {
isLoading = false;
_name = toBeginningOfSentenceCase(_json['results'][0]['name']['first']);
_lastName =
toBeginningOfSentenceCase(_json['results'][0]['name']['last']);
_image = _json['results'][0]['picture']['large'];
print('Done loading...');
});
} else {
throw Exception('Failed to load backend data');
}
}
#override
void initState() {
super.initState();
_fetchBackendData().then((result) {
print('Feched data from backend');
});
}
_LandOffer({this.startPoint, this.endPoint});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Describe your offer '),
automaticallyImplyLeading: true,
),
body: isLoading
? Center(
child: CircularProgressIndicator(),
)
: ListView(
children: <Widget>[
Column(
children: <Widget>[
Row(
children: <Widget>[
Image(
image: NetworkImage(_image),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'First name: $_name',
textAlign: TextAlign.left,
),
Text(
'Last name: $_lastName',
textAlign: TextAlign.left,
),
Text('Rating'),
SmoothStarRating(
rating: 3.2,
),
],
),
],
),
],
),
],
));
}
}
which in additions displays the image like this:
But it seems like there is a padding added to a text.
I would like to move the text to the very top, and add a padding, should I need one.
Also, if I apply the padding to the image, it applies the padding to the whole row, which is not the desired result.
Thank you in advance for your help.
Because your image height are bigger one in row, if you add padding(assume both top,bottom,left,right) to image, the row height will be expanded too. Unless you only want padding(left, right) or you need constraint image height.
Row(
crossAxisAlignment: CrossAxisAlignment.start, //<-- move text top
children: <Widget>[
Padding(
padding: EdgeInsets.all(5),
child: Image(
image: NetworkImage(_image),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start, //<-- move text top
children: <Widget>[
Text(
'First name: $_name',
textAlign: TextAlign.left,
),
Text(
'Last name: $_lastName',
textAlign: TextAlign.left,
),
Text('Rating'),
SmoothStarRating(
rating: 3.2,
),
],
),
],
),

How to show rich message like Google-Assistant-output Basic Card on Flutter app

I made a chatbot with dialogflow and (https://github.com/diegodalbosco/flutter_dialogflow) this is working normaly with simple text response.
Then when I add Google Assistant on a respond (Intent) like: answers with Basic Card.
When i lunch this application on android phone, I can write normally and i can see normal answers. But when i try to write "Query" or "Intent" something to call the Google Assistant Basic Card response, application stop and error.
Could someone help?
I believe that Google Assistant response is supported by Flutter?
Could some one explain how to set, display rich message of Google Assistant response like Basic Card in flutter App?
ThankYou
I haded: "
and
"ChatMessage message = new ChatMessage(
text: response.queryResult.fulfillmentText
?? new df.BasicCard(),"
and
"new Container(
margin: const EdgeInsets.only(top: 5.0),
child: new Text(text?? new df.BasicCard()),
),
"
looking for docs on:
https://pub.dev/documentation/flutter_dialogflow_v2/latest/model_query_result/QueryResult/fulfillmentMessages.html
for fulfillmentMessages property
-
https://pub.dev/documentation/flutter_dialogflow_v2/latest/model_message_basic_card/BasicCard-class.html
for BasicCard
-
https://pub.dev/documentation/flutter_dialogflow_v2/latest/model_query_result/QueryResult-class.html
for QueryResult class
import 'package:flutter_dialogflow_v2/flutter_dialogflow_v2.dart' as df;
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Example Dialogflow Flutter',
theme: new ThemeData(
primarySwatch: Colors.deepOrange,
),
home: new MyHomePage(
title: 'Flutter Demo Dialogflow',
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
final List<df.BasicCard> fulfillmentMessages = <df.BasicCard>[];
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final List<ChatMessage> _messages = <ChatMessage>[];
final TextEditingController _textController = new TextEditingController();
Widget _buildTextComposer() {
return new IconTheme(
data: new IconThemeData(color: Theme.of(context).accentColor),
child: new Container(
margin: const EdgeInsets.symmetric(horizontal: 8.0),
child: new Row(
children: <Widget>[
new Flexible(
child: new TextField(
controller: _textController,
onSubmitted: _handleSubmitted,
decoration:
new InputDecoration.collapsed(hintText: 'Send a message'),
),
),
new Container(
margin: new EdgeInsets.symmetric(horizontal: 4.0),
child: new IconButton(
icon: new Icon(Icons.send),
onPressed: () => _handleSubmitted(_textController.text)),
),
],
),
),
);
}
void response(query) async {
_textController.clear();
df.AuthGoogle authGoogle =
await df.AuthGoogle(fileJson: 'assets/project-id.json').build();
df.Dialogflow dialogflow =
df.Dialogflow(authGoogle: authGoogle, sessionId: '123456');
df.DetectIntentResponse response = await dialogflow.detectIntent(query);
ChatMessage message = new ChatMessage(
text: response.queryResult.fulfillmentText
?? new df.BasicCard()
,
name: 'Bot',
type: false,
);
setState(() {
_messages.insert(0, message);
});
}
void _handleSubmitted(String text) {
_textController.clear();
ChatMessage message = new ChatMessage(
text: text,
name: 'Rances',
type: true,
);
setState(() {
_messages.insert(0, message);
});
response(text);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Dialogflow V2'),
),
body: new Column(children: <Widget>[
new Flexible(
child: new ListView.builder(
padding: new EdgeInsets.all(8.0),
reverse: true,
itemBuilder: (_, int index) => _messages[index],
itemCount: _messages.length,
)),
new Divider(height: 1.0),
new Container(
decoration: new BoxDecoration(color: Theme.of(context).cardColor),
child: _buildTextComposer(),
),
]),
);
}
}
class ChatMessage extends StatelessWidget {
ChatMessage({this.text, this.name, this.type});
final String text;
final String name;
final bool type;
List<Widget> otherMessage(context) {
return <Widget>[
new Container(
margin: const EdgeInsets.only(right: 16.0),
child: new CircleAvatar(child: new Image.asset('img/placeholder.png')),
),
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(this.name,
style: new TextStyle(fontWeight: FontWeight.bold)),
new Container(
margin: const EdgeInsets.only(top: 5.0),
child: new Text(text?? new df.BasicCard()),
),
],
),
),
];
}
List<Widget> myMessage(context) {
return <Widget>[
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
new Text(this.name, style: Theme.of(context).textTheme.subhead),
new Container(
margin: const EdgeInsets.only(top: 5.0),
child: new Text(text),
),
],
),
),
new Container(
margin: const EdgeInsets.only(left: 16.0),
child: new CircleAvatar(child: new Text(this.name[0])),
),
];
}
#override
Widget build(BuildContext context) {
return new Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: this.type ? myMessage(context) : otherMessage(context),
),
);
}
}
I expect the output like:
when I ask the preset Intent for BasicCard, the app show response with BasicCard but the actual output is
error:
"
E/flutter ( 4203): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: NoSuchMethodError: The method '[]' was called on null.
E/flutter ( 4203): Receiver: null
E/flutter ( 4203): Tried calling: "
and no response on the flutter chat App.
For Google Assistant Actions, you need to use one of our client libraries (Node.js or Java). The Dialogflow library are designed to support other platforms but not the Google Assistant specifically (some things might work cross-platform, but other like cards will not).

Resources