Flutter list, chips and MultiSelect - flutter

I am trying to transfer the result of a query to a list but it is not working properly.
Below you will find the source code, it will be more clear.
I'm getting this error "type 'List' is not a subtype of type 'List'"
if the error is clear, I do not understand how to fix that.
I would like to get _allResults (contextName) into the list _context.
Many thanks for your help.
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:gtd_official_sharped_focused/models/context.dart';
import 'package:multi_select_flutter/multi_select_flutter.dart';
String taskImportant;
String taskUrgent;
class EngagePage_Sept_2021 extends StatefulWidget {
EngagePage_Sept_2021({Key key, }):super(key:key);//this.title}) : super(key: key);
// final String title;
#override
_EngagePage_Sept_2021State createState() => _EngagePage_Sept_2021State();
}
class _EngagePage_Sept_2021State extends State<EngagePage_Sept_2021> {
TextEditingController _searchController = TextEditingController();
Future resultsLoaded;
List _allResults = [];
List _resultsList = [];
#override
void initState() {
super.initState();
_selectedContext = _allResults;//_context;
_searchController.addListener(_onSearchChanged);
}
#override
void dispose(){
_searchController.removeListener(_onSearchChanged);
_searchController.dispose();
super.dispose();
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
resultsLoaded = getUsersListOfTasksStreamSnapshots();
}
_onSearchChanged() {
searchResultsList();
}
/*static List<Contexts> _monTest = [
Contexts(contextName: ),
];
*/
static List<Contexts> _context = [. //Here, I would prefer to store the data.docs
Contexts(id: '1', contextName: "name 1"),
Contexts(id: '2', contextName: "name 2"),
Contexts(id: '3', contextName: "name 3"),
];
// static List<Contexts> _test = _allResults;
final _itemsContext = _context
.map((context) => MultiSelectItem<Contexts>(context, context.contextName))
.toList();
List<Contexts> _selectedContext = [];
final _multiSelectKeyContext = GlobalKey<FormFieldState>();
final _multiSelectKeyStatus = GlobalKey<FormFieldState>();
final _multiSelectKey4 = GlobalKey<FormFieldState>();
final _multiSelectKeyTime = GlobalKey<FormFieldState>();
searchResultsList() {
var showResults = [];
if(_searchController.text != "") {
for(var taskSnapshot in _allResults){
var title = Contexts.fromSnapshot(taskSnapshot).contextName.toLowerCase();
if(title.contains(_searchController.text.toLowerCase())) {
showResults.add(taskSnapshot);
}
}
} else {
showResults = List.from(_allResults);
}
setState(() {
_resultsList = showResults;
});
}
getUsersListOfTasksStreamSnapshots() async {
var data = await FirebaseFirestore.instance
.collection('Users')
.doc(FirebaseAuth.instance.currentUser.uid)
.collection('contexts')
.get();
setState(() {
_allResults = data.docs;
print(_allResults);
});
searchResultsList();
return 'complete';
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('TEST CHIP'),
),
drawer: MyMenu(),
backgroundColor: Colors.white,
body: SingleChildScrollView(
child: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(20),
child: Column(
children: <Widget>[
//################################################################################################
// CONTEXT - MultiSelectBottomSheetField with validators
//################################################################################################
MultiSelectBottomSheetField<Contexts>(
key: _multiSelectKeyContext,
initialChildSize: 0.7,
maxChildSize: 0.95,
title: Text("Context"),
buttonText: Text("Context",style: TextStyle(fontSize: 18),),
items: _itemsContext,
searchable: true,
validator: (values) {
if (values == null || values.isEmpty) {
return "";
}
List<String> names = values.map((e) => e.contextName).toList();
return null;
},
onConfirm: (values) {
setState(() {
_selectedContext = values;
});
_multiSelectKeyContext.currentState.validate();
},
chipDisplay: MultiSelectChipDisplay(
onTap: (item) {
setState(() {
_selectedContext.remove(item);
});
_multiSelectKeyContext.currentState.validate();
},
),
),
SizedBox(height: 40),
//################################################################################################
// STATUS - MultiSelectBottomSheetField with validators
//################################################################################################
],
),
],
),
),
),
);
}
}
Model context
import 'package:cloud_firestore/cloud_firestore.dart';
class Contexts {
String id;
String contextName;
Contexts({
this.id,
this.contextName,
});
// formatting for upload to Firebase when creating the trip
Map<String, dynamic> toJson() =>
{
'context_Name': contextName,
};
//creating a Task object from a firebase snapshot
Contexts.fromSnapshot(DocumentSnapshot snapshot) :
id = snapshot.id,
contextName = snapshot['context_Name'];
}

Related

How to fetch data API to dropdown

how do I call the API data into the dropdown I have done several times, when I used local data in the form of a String list I managed to call the data, but when I tried to call from the API data the result was empty and the results in the dropdown did not display any data
Future<List<Agama>> getAgama() async {
String url = Constant.baseURL;
String token = await UtilSharedPreferences.getToken();
final response = await http.get(
Uri.parse(
'$url/auth/mhs_siakad/dosen',
),
headers: {
'Authorization': 'Bearer $token',
},
);
print(response.statusCode);
print(response.body);
if (response.statusCode == 200) {
final result =
json.decode(response.body)['nm_agama'] as Map<String, dynamic>;
UserBiodata agama = UserBiodata.fromJson(result);
List<Agama> l = agama.data ?? [];
return l;
} else {
throw Exception();
}
}
in widget
List<Agama>? religion = [];
#override
void initState() {
super.initState();
BiodataProvider().getAgama();
}
var dropdownAgama;
...
FutureBuilder(
future: BiodataProvider().getBiodata(),
builder: (context, snapshot) {
if (snapshot.hasData) {
print(' ini Agama $religion');
return Column(
children: [
Text(
snapshot.data!.data!.name.toString(),
style: bold5,
),
DropdownButton(
hint: const Text('Religion'),
items: religion!.map((item) {
return DropdownMenuItem(
value: item.nmAgama.toString(),
child: Text(item.idAgama.toString()),
);
}).toList(),
onChanged: (newVal) {
setState(() {
dropdownAgama = newVal;
});
},
value: dropdownAgama,
),
],
);
} else {
return const Text('No Data');
}
}),
...
this is the model i am using which is converted from API
class Agama {
String? id;
String? idAgama;
String? nmAgama;
String? createdAt;
String? updatedAt;
dynamic createdBy;
dynamic updatedBy;
Agama(
{this.id,
this.idAgama,
this.nmAgama,
this.createdAt,
this.updatedAt,
this.createdBy,
this.updatedBy});
Agama.fromJson(Map<String, dynamic> json) {
id = json['id'];
idAgama = json['id_agama'];
nmAgama = json['nm_agama'];
createdAt = json['created_at'];
updatedAt = json['updated_at'];
createdBy = json['created_by'];
updatedBy = json['updated_by'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['id_agama'] = idAgama;
data['nm_agama'] = nmAgama;
data['created_at'] = createdAt;
data['updated_at'] = updatedAt;
data['created_by'] = createdBy;
data['updated_by'] = updatedBy;
return data;
}
}
it looks like you are not assigning your api data to the
List<Agama>? religion;
you can solve this by either mapping your snapshot data directly:
#override
void initState() {
super.initState();
BiodataProvider().getAgama();
}
var dropdownAgama;
...
FutureBuilder(
future: BiodataProvider().getBiodata(),
builder: (context, snapshot) {
if (snapshot.hasData) {
print(' ini Agama $religion');
return Column(
children: [
Text(
snapshot.data!.data!.name.toString(),
style: bold5,
),
DropdownButton(
hint: const Text('Religion'),
items: snapshot.data!.data!.map((item) {
return DropdownMenuItem(
value: item.nmAgama.toString(),
child: Text(item.idAgama.toString()),
);
}).toList(),
onChanged: (newVal) {
setState(() {
dropdownAgama = newVal;
});
},
value: dropdownAgama,
),
],
);
} else {
return const Text('No Data');
}
}),
or
by assigning the snapshot data to your list:
List<Agama>? religion = [];
#override
void initState() {
super.initState();
BiodataProvider().getAgama();
}
var dropdownAgama;
...
FutureBuilder(
future: BiodataProvider().getBiodata(),
builder: (context, snapshot) {
if (snapshot.hasData) {
WidgetsBinding.instance.addPostFrameCallback((_) {
setState((){
religion = snapshot.data!.data;
})
});
print(' ini Agama $religion');
return Column(
children: [
Text(
snapshot.data!.data!.name.toString(),
style: bold5,
),
DropdownButton(
hint: const Text('Religion'),
items: religion!.map((item) {
return DropdownMenuItem(
value: item.nmAgama.toString(),
child: Text(item.idAgama.toString()),
);
}).toList(),
onChanged: (newVal) {
setState(() {
dropdownAgama = newVal;
});
},
value: dropdownAgama,
),
],
);
} else {
return const Text('No Data');
}
}),
hope this helps!
Solution
In Controller Class,
Initialize your Future Method as your Model : Future<List<LeaveModel>> getLeaves(){}
create a List of Obj for Custom Class like this :
List<LeaveModel> leaveTypeObjList = [];
After fetching data from API add the datas in obj list via Object
type :LeaveModel leaveTypeObj = LeaveModel(leaveTypeResponseList[i]["LEAVE_TYPE_EN"]);
And in loop add it to your obj list: leaveTypeObjList.add(leaveTypeObj);
** In widget class at AsyncSnapshot use your List of Generics like this :
AsyncSnapshot<List<LeaveModel>>.
Demo Code
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main(List<String> args) {
runApp(MyHome());
}
class MyHome extends StatelessWidget {
const MyHome({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyApp(),
);
}
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<String> leaveTypeList = [];
int currentLeaveType = 0;
String? value;
String? selectedLeaveType;
late Future<List<LeaveModel>> futureLeaves;
#override
void initState() {
super.initState();
futureLeaves = FoodTypeController().getLeaves();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
height: double.infinity,
width: double.infinity,
child: Row(
children: [
Text(
"Leave Type = ",
style: TextStyle(fontSize: 24.0),
),
FutureBuilder(
future: futureLeaves,
builder: ((BuildContext context,
AsyncSnapshot<List<LeaveModel>> snapshot) {
if (snapshot.hasData) {
leaveTypeList = [];
List<LeaveModel>? LeaveTypes = snapshot.data;
for (int i = 0; i < LeaveTypes!.length; i++) {
leaveTypeList.add(LeaveTypes[i].leaveTypes!);
}
return SizedBox(
width: 200,
height: 50,
child: Container(
padding: EdgeInsets.only(left: 2.0, right: 4.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
border: Border.all(color: Colors.black, width: 1)),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
borderRadius: BorderRadius.circular(12),
value: currentLeaveType == null? null: leaveTypeList[currentLeaveType],
icon: Icon(Icons.arrow_drop_down_rounded),
items: leaveTypeList.map(buildMenuItem).toList(),
onChanged: (value) => setState(() {
currentLeaveType = leaveTypeList.indexOf(value.toString());
this.value = value;
selectedLeaveType = this.value;
}),
),
),
),
);
} else if (snapshot.hasError) {
return const Text("Error to load Snapshot");
} else {
return const CircularProgressIndicator();
}
})),
],
),
),
);
}
DropdownMenuItem<String> buildMenuItem(String item) => DropdownMenuItem(
value: item,
child: Text(
item.toString(),
style: TextStyle(fontWeight: FontWeight.w400, fontSize: 24.0),
),
);
}
class LeaveModel {
String? leaveTypes;
LeaveModel(this.leaveTypes);
}
class FoodTypeController {
Future<List<LeaveModel>> getLeaves() async {
List<LeaveModel> leaveTypeObjList = [];
String url = "";
http.Response response =
await http.post(Uri.parse(url), body: {"user": "", "pass": ""});
if (response.statusCode == 200) {
List leaveTypeResponseList = jsonDecode(response.body);
for (int i = 0; i < leaveTypeResponseList.length; i++) {
LeaveModel leaveTypeObj =
LeaveModel(leaveTypeResponseList[i]["LEAVE_TYPE"]);
leaveTypeObjList.add(leaveTypeObj);
}
return leaveTypeObjList;
} else {
throw Exception("Error to load data in Leave Controller");
}
}
}
Response
Visual

Although there is no error in the application that I want to show the weather from the internet, a white screen appears

launchUrl not working
import 'package:flutter/material.dart';
import 'package:haber_app/data/new_service.dart';
import 'package:haber_app/models/articles.dart';
import 'package:url_launcher/url_launcher.dart';
class Home extends StatefulWidget {
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
List<Articles> articles = [];
#override
void initState() {
NewsService.getNews().then((value) {
setState(() {
articles = value!;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Haberler'),
centerTitle: true,
),
body: Center(
child: ListView.builder(
itemCount: articles.length,
itemBuilder: (context, index) {
return Card(
child: Column(
children: [
Image.network(articles[index].urlToImage!),
ListTile(
leading: Icon(Icons.arrow_drop_down_circle),
title: Text(articles[index].title!),
subtitle: Text(articles[index].author!),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'açıklama açıklama açıklamaaçıklama açıklamaaçıklama'),
),
ButtonBar(
alignment: MainAxisAlignment.start,
children: [
ElevatedButton(
onPressed: () async {
await launchUrl(articles[index].url);
},
child: Text('Habere git'))
],
)
],
),
);
})),
);
}
}
Link of the code: https://github.com/ghedtoboss/haber_app
I am making a pull request, check the changes and merge. haber_app/pull/1
Changes are on
source.dart
class Source {
String? id;
String? name;
Source({this.id, this.name});
Source.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = Map<String, dynamic>();
data['id'] = id;
data['name'] = name;
return data;
}
}
news.dart
import 'articles.dart';
class News {
String? status;
int? totalResults;
List<Articles>? articles;
News({this.status, this.totalResults, this.articles});
News.fromJson(Map<String, dynamic> json) {
status = json['status'];
totalResults = json['totalResults'];
if (json['articles'] != null) {
articles = <Articles>[];
json['articles'].forEach((v) {
print(v);
articles!.add(Articles.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = Map<String, dynamic>();
data['status'] = status;
data['totalResults'] = totalResults;
if (articles != null) {
data['articles'] = articles!.map((v) => v.toJson()).toList();
}
return data;
}
}
NewsService
import 'package:haber_app/models/articles.dart';
import 'package:haber_app/models/news.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class NewsService {
static NewsService _singleton = NewsService._internal();
NewsService._internal();
factory NewsService() {
return _singleton;
}
static Future<List<Articles>?> getNews() async {
String api =
'https://newsapi.org/v2/top-headlines?country=tr&category=business&apiKey=0002834b74c04acd987883986ea38f96';
final Uri url = Uri.parse(api);
final response = await http.post(url);
if (response.body.isNotEmpty) {
final responseJson = json.decode(response.body);
News news = News.fromJson(responseJson);
return news.articles;
}
return null;
}
}
On body
import 'package:flutter/material.dart';
import 'package:haber_app/data/new_service.dart';
import 'package:haber_app/models/articles.dart';
import 'package:url_launcher/url_launcher.dart';
class Home extends StatefulWidget {
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
List<Articles> articles = [];
#override
void initState() {
super.initState();
loadData();
}
loadData() async {
NewsService.getNews().then((value) {
print(value);
setState(() {
articles = value ?? [];
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Haberler'),
centerTitle: true,
),
body: Center(
child: articles.isEmpty
? Text("loading or something")
: ListView.builder(
itemCount: articles.length,
itemBuilder: (context, index) {
return Card(
child: Column(
children: [
if (articles[index].urlToImage != null)
Image.network(articles[index].urlToImage!),
ListTile(
leading: Icon(Icons.arrow_drop_down_circle),
title: Text(articles[index].title ?? ""),
subtitle: Text(articles[index].author ?? ""),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'açıklama açıklama açıklamaaçıklama açıklamaaçıklama'),
),
ButtonBar(
alignment: MainAxisAlignment.start,
children: [
ElevatedButton(
onPressed: () async {
if (articles[index].url == null) {
return;
}
await launchUrl(
Uri.parse(articles[index].url!));
},
child: Text('Habere git'))
],
)
],
),
);
})),
);
}
}
You need to use Uri to launch
onPressed: () async {
if (articles[index].url == null) {
return;
}
await launchUrl(
Uri.parse(articles[index].url!));
},
Also make sure to set up the configurationsection
More about url_launcher

Multiple showDialog for validation

On my project I need to use several showDialog one after the other.
For user creation, I use a SearchField widget to retrieve info from a table related to the user.
If the SearchField value does not exist I would like to propose the creation. Depending on the choice either the form is in error or I propose to register the user.
For this I use a showDialog in the validator of the SearchField and an if validator is correct.
My problem is that my second dialog box is displayed before validating the first one and even above that of the SearchField.
What is the correct way to do this?
Thank you,
class InformationsPage extends StatefulWidget {
const InformationsPage({
required Key key,
required this.user,
required this.type,
}) : super(key: key);
final User user;
final FenType type;
#override
InformationsPageState createState() => InformationsPageState();
}
class InformationsPageState extends State<InformationsPage>
with AutomaticKeepAliveClientMixin {
InformationsPageState({this.user});
final User? user;
late UserApi _api;
#override
bool get wantKeepAlive => true;
bool _familyIsCreated = false;
late User userSaved;
late FenType type;
//Info Form
var _pseudoController = TextEditingController();
var _familyController = TextEditingController();
#override
void initState() {
super.initState();
_api = UserApi();
_pseudoController = TextEditingController(text: widget.user.pseudo);
_familyController = TextEditingController(text: widget.user.familyName);
userSaved = User.fromUser();
type = widget.type;
}
#override
void dispose() {
_pseudoController.dispose();
_familyController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
super.build(context);
return Column(
children: <Widget>[
FutureBuilder(
future: _api.getFamilies(),
builder: (context, AsyncSnapshot<List<Family>> snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(
"Something wrong with message: ${snapshot.error.toString()}"));
} else if (snapshot.connectionState == ConnectionState.done) {
List<Family> _list = snapshot.data!;
return _buildDropdownSearchFamilies(_list);
} else {
return const Center(child: CircularProgressIndicator());
}
}),
TextFormField(
readOnly: type == FenType.read ? true : false,
inputFormatters: [LowerCaseTextFormatter()],
controller: _pseudoController,
onSaved: (value) => userSaved.pseudo = value,
decoration: const InputDecoration(
icon: Icon(Icons.person),
hintText: 'Pseudo',
labelText: 'Pseudo',
),
validator: (value) =>
value!.isEmpty ? 'Obligatory' : null),
],
);
}
int? _contains(List<Family> list, String? name) {
int? res = -1;
for (Family element in list) {
if (element.name == name) {
res = element.id;
break;
}
}
return res;
}
Widget _buildDropdownSearchFamilies(List<Family> _list) {
return SearchField(
controller: _familyController,
suggestions: _list
.map((e) =>
SearchFieldListItem(e.name!, child: Text(e.name!), item: e.id))
.toList(),
hint: 'Family',
validator: (x) {
if (x!.isEmpty) {
userSaved.familyId = null;
userSaved.familyName = null;
return null;
}
int? id = _contains(_list, x);
if (id == -1) {
userSaved.familyId == null;
showDiaglog(x);
if (userSaved.familyId != null) {
return null;
} else {
return 'Family not exist';
}
} else {
userSaved.familyId = id;
userSaved.familyName = x;
return null;
}
},
searchInputDecoration: const InputDecoration(
labelText: 'Family', icon: Icon(Icons.groups)),
itemHeight: 50,
onTap: (x) {
userSaved.familyId = x.item as int?;
userSaved.familyName = x.child.toString();
});
}
showDiaglog(String family) async {
String title = "Family";
String message =
"Family $family not exist. Create ?";
String textKoButton = "no";
String textOkButton = "yes";
MyDialog alert = MyDialog(
title: title,
message: message,
onPressedKo: koButtonPressed(),
onPressedOk: okButtonPressed(family),
textKoButton: textKoButton,
textOkButton: textOkButton);
await showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
void Function() koButtonPressed() => () {
_familyIsCreated = false;
Navigator.of(context).pop(false);
};
void Function() okButtonPressed(family) => () {
_save(family);
Navigator.of(context).pop();
};
void _save(family) async {
UserApi apiUser = UserApi();
Family oldF = Family.empty();
Family newF = Family.empty();
newF.name = family;
newF.createdAt = oldF.createdAt;
newF.deletedAt = newF.deletedAt;
Map<String, dynamic> data = oldF.toJson(newF);
int res = -1;
res = await apiUser.createFamily(data);
SnackBar snackBar;
if (res != -1) {
snackBar = MyWidget.okSnackBar('Family created');
userSaved.familyId = res;
userSaved.familyName = family;
} else {
snackBar = MyWidget.koSnackBar(
'Family not created');
userSaved.familyId = null;
userSaved.familyName = null;
}
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
}
My form :
class UserFormPage extends StatefulWidget {
static const String routeName = '/admin/user-form';
final User? user;
final FenType fenType;
const UserFormPage({Key? key, required this.user, required this.fenType})
: super(key: key);
#override
_UserFormPageState createState() => _UserFormPageState();
}
class _UserFormPageState extends State<UserFormPage>
with SingleTickerProviderStateMixin {
static final GlobalKey<FormState> _formKey =
GlobalKey<FormState>(debugLabel: '_appState');
static final GlobalKey<InformationsPageState> _infoKey =
GlobalKey<InformationsPageState>();
late TabController _controller;
late User _user;
late User _userSaved;
#override
void initState() {
super.initState();
_controller = TabController(vsync: this, length: 2);
_user = widget.user!;
_userSaved = widget.user!;
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () =>
Navigator.pushReplacementNamed(context, Routes.admUserList),
),
title: const Text('Member'),
actions: <Widget>[
Visibility(
visible: widget.fenType != FenType.read ? true : false,
child: IconButton(
icon: const Icon(Icons.save),
onPressed: () {
if (!_formKey.currentState!.validate()) {
return;
}
showDiaglog();
},
))
],
bottom: TabBar(
controller: _controller,
tabs: const [
Tab(text: 'Info'),
Tab(text: 'Others'),
],
),
),
body: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Flexible(
child: TabBarView(
controller: _controller,
children: <Widget>[
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InformationsPage(
user: _user,
key: _infoKey,
type: widget.fenType),
])),
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
DetailsPage(
user: _user,
key: _detailsKey,
type: widget.fenType)
],
)),
],
))
],
))),
);
}
void _save() async {
final infoState = _infoKey.currentState;
_userSaved = infoState?.userSaved ?? _user;
_userSaved.pseudo = infoState?.userSaved.pseudo ?? _user.pseudo;
Map<String, dynamic> data = _user.userToJsonClean(_userSaved);
if (!_userSaved.userIsUpdated()) {
final outSnackBar = MyWidget.okSnackBar('Not update');
ScaffoldMessenger.of(context).showSnackBar(outSnackBar);
} else {
UserApi apiUser = UserApi();
bool res = false;
res = widget.fenType == FenType.update
? await apiUser.update(data)
: await apiUser.create(data);
SnackBar snackBar;
res
? snackBar = MyWidget.okSnackBar('Member saved')
: snackBar = MyWidget.koSnackBar(
'Member not saved');
ScaffoldMessenger.of(context).showSnackBar(snackBar);
_user = _userSaved;
if (widget.fenType == FenType.create) {
Navigator.of(context).popAndPushNamed(Routes.admUserList);
}
}
}
void showDiaglog() {
String pseudo = _userSaved.pseudo!;
String title = "Save";
String message = widget.fenType == FenType.create
? "Create member $pseudo ?"
: "Save meber $pseudo ?";
String textKoButton = "no";
String textOkButton = "yes";
MyDialog alert = MyDialog(
title: title,
message: message,
onPressedKo: koButtonPressed(),
onPressedOk: okButtonPressed(),
textKoButton: textKoButton,
textOkButton: textOkButton);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
void Function() koButtonPressed() => () {
Navigator.of(context).pop(false);
};
void Function() okButtonPressed() => () {
_formKey.currentState!.save();
_save();
Navigator.of(context).pop();
};
}
I resolve this problem to modified the widget SearchField to a DropdownSearch.

Flutter display server data / response from json

I have built a page which reads the json from recipeURL and I wish for it to display the product_name value in the json file. However for some reason my future fetchData () class isn't being read as none of the text in my if else statement is being displayed. Am I missing a simple oversight here?
EDIT: The main dart file is my main screen. This is where my navbar is created. Users are redirected to other pages when they click on the corresponding icon. Im having trouble passing BarcodePage(title:title); as parameters in my main file,26th line, can be found under Class MyAppState extends State<MyApp> {
My main dart file:
import 'package:flutter/material.dart';
import 'pages/BarcodePage.dart';
import 'pages/FoodPage.dart';
import 'pages/RecipePage.dart';
import 'pages/ShoppingPage.dart';
void main() {
runApp(MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()),);
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState(){
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
int _selectedPage =0;
final _pageOptions= [
FoodPage(),
RecipePage(),
BarcodePage(title: ,),
ShoppingPage(),
];
#override
Widget build(BuildContext context) {
return MaterialApp(
//title: 'Best B4',
theme: ThemeData(
primarySwatch: Colors.teal,),
debugShowCheckedModeBanner: false,
home: Scaffold (
appBar: AppBar(
title:Text(
'BestB4',
style: TextStyle(
fontFamily: 'PacificoRegular',
fontSize: 30,
),
),
backgroundColor: Colors.teal,
elevation: 20,
actions: [
IconButton(
icon: Icon(Icons.qr_code_2_rounded),
tooltip: 'Add item',
onPressed:(){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => BarcodePage()));
},
)
],
//ONPRESSED MENU OPEN
),
body:_pageOptions[_selectedPage],
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.teal,
selectedItemColor: Colors.white,
unselectedItemColor: Colors.white70,
iconSize: 40,
selectedFontSize: 15,
unselectedFontSize: 15,
currentIndex:_selectedPage,
onTap: (int index) {
setState(() {
_selectedPage = index;
});
},
items: [
BottomNavigationBarItem(
icon:Icon(Icons.restaurant_rounded),
label: 'Food',
), //, title:Text('Food')
BottomNavigationBarItem(
icon:Icon(Icons.menu_book_rounded),
label:'Recipes',
),//, title:Text('Recipes')
BottomNavigationBarItem(
icon:Icon(Icons.add_outlined),
label:'Add',
),//, title:Text('Add')
BottomNavigationBarItem(
icon:Icon(Icons.shopping_cart_rounded),
label:'Shopping',
),//,title:Text('Shopping')
],
),
),
);
}
}
My BarcodePage dart file:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as p;
import 'package:flutter/services.dart';
import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:http/http.dart';
class BarcodePage extends StatefulWidget{
const BarcodePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_BarcodePageState createState() => _BarcodePageState();
}
var futuredata = {};
class _BarcodePageState extends State<BarcodePage> {
int counter=0;
String result= "";
Future _scanBarcode() async{
try{
ScanResult scanResult = await BarcodeScanner.scan();
String barcodeResult = scanResult.rawContent;
setState(() {
result = barcodeResult;
});
} on PlatformException catch (ex) {
if (ex.code == BarcodeScanner.cameraAccessDenied) {
setState((){
result = "CAMERA PERMISSION WAS DENIED. \n EDIT THIS IN YOUR SETTINGS";
});
}else {
setState(() {
result = "404 ERROR UNKNOWN $ex";
});
}
} on FormatException {
setState(() {
result = "SCAN AN ITEM";
});
} catch (ex){
setState(() {
result = "404 ERROR UNKNOWN $ex";
});
}
}
#override
void initState() {}
fetchmydata() async {
var request = p.Request(
'GET',
Uri.parse(
'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));
StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
var data = await response.stream.bytesToString();
futuredata = json.decode(data);
} else {
print(response.reasonPhrase);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.teal,
title:Text('Add an item',
style: TextStyle(
fontFamily: 'Fredoka',
fontSize: 25,
),
),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(
child: Container(
child: CircularProgressIndicator(),
height: 50,
width: 50,
),
);
else if (snapshot.connectionState == ConnectionState.done)
return ListTile(
title: Text(futuredata["product"]["product_name"].toString()),
subtitle: Text("France:" +
futuredata["product"]["product_name_en"].toString()),
);
else {
return Container(
child: CircularProgressIndicator(),
height: 50,
width: 50,
);
}
},
future: fetchmydata(),
)
],
),
floatingActionButton: FloatingActionButton.extended(
backgroundColor: Color.fromRGBO(51, 171, 160, 100),
icon: Icon(Icons.camera_alt),
label: Text("Scan"),
onPressed: _scanBarcode,
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
The Json file looks like this:
JSON LINK: https://world.openfoodfacts.org/api/v0/product/5060391623139.json
You can read your json like this
var futuredata = {};
var productname= futuredata["product"]["product_name"]
Your fetch method like this
fetchmydata() async {
var request = p.Request(
'GET',
Uri.parse(
'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));
StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
var data = await response.stream.bytesToString();
futuredata = json.decode(data);
} else {
print(response.reasonPhrase);
}
}
With model Class
SampleModel? Mymodel = null;
fetchmydata() async {
var request = p.Request(
'GET',
Uri.parse(
'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));
StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
var data = await response.stream.bytesToString();
futuredata = json.decode(data);
Mymodel = SampleModel.fromJson(futuredata);
} else {
print(response.reasonPhrase);
}
}
in the method we first read data from json as string or text
then we decode the string type or text from server to map type
SampleCode Dartpad live code check
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:http/http.dart' as p;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
var futuredata = {};
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
#override
void initState() {}
fetchmydata() async {
var request = p.Request(
'GET',
Uri.parse(
'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));
StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
var data = await response.stream.bytesToString();
futuredata = json.decode(data);
} else {
print(response.reasonPhrase);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(
child: Container(
child: CircularProgressIndicator(),
height: 50,
width: 50,
),
);
else if (snapshot.connectionState == ConnectionState.done)
return ListTile(
title: Text(futuredata["product"]["product_name"].toString()),
subtitle: Text("France:" +
futuredata["product"]["product_name_en"].toString()),
);
else {
return Container(
child: CircularProgressIndicator(),
height: 50,
width: 50,
);
}
},
future: fetchmydata(),
)
],
),
);
}
}
Sample ModelClass
///
/// Code generated by jsonToDartModel https://ashamp.github.io/jsonToDartModel/
///
class SampleModelProduct {
/*
{
"_id": "5060391623139",
"_keywords": [
"peanut"
],
"product_name": "Peanut butter",
"product_name_en": "Peanut butter",
"product_name_fr": "Peanut butter"
}
*/
String? Id;
List<String?>? Keywords;
String? productName;
String? productNameEn;
String? productNameFr;
SampleModelProduct({
this.Id,
this.Keywords,
this.productName,
this.productNameEn,
this.productNameFr,
});
SampleModelProduct.fromJson(Map<String, dynamic> json) {
Id = json['_id']?.toString();
if (json['_keywords'] != null) {
final v = json['_keywords'];
final arr0 = <String>[];
v.forEach((v) {
arr0.add(v.toString());
});
Keywords = arr0;
}
productName = json['product_name']?.toString();
productNameEn = json['product_name_en']?.toString();
productNameFr = json['product_name_fr']?.toString();
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['_id'] = Id;
if (Keywords != null) {
final v = Keywords;
final arr0 = [];
v!.forEach((v) {
arr0.add(v);
});
data['_keywords'] = arr0;
}
data['product_name'] = productName;
data['product_name_en'] = productNameEn;
data['product_name_fr'] = productNameFr;
return data;
}
}
class SampleModel {
/*
{
"code": "5060391623139",
"product": {
"_id": "5060391623139",
"_keywords": [
"peanut"
],
"product_name": "Peanut butter",
"product_name_en": "Peanut butter",
"product_name_fr": "Peanut butter"
},
"status": 1,
"status_verbose": "product found"
}
*/
String? code;
SampleModelProduct? product;
int? status;
String? statusVerbose;
SampleModel({
this.code,
this.product,
this.status,
this.statusVerbose,
});
SampleModel.fromJson(Map<String, dynamic> json) {
code = json['code']?.toString();
product = (json['product'] != null)
? SampleModelProduct.fromJson(json['product'])
: null;
status = json['status']?.toInt();
statusVerbose = json['status_verbose']?.toString();
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['code'] = code;
if (product != null) {
data['product'] = product!.toJson();
}
data['status'] = status;
data['status_verbose'] = statusVerbose;
return data;
}
}
try creating a .g.dart file using flutter packages pub run build_runner build. flutter automatically will create your binding class factory. once you have the binding classes created flutter will automatically code your binding class, including nested classes. I personally think automation is the way to handle all interactions with json from the server. The reason you want to use the future .g.dart code generator is to reduce the possibility of error and incorrect type casting.
file.dart
factory ProductView.fromJson(Map<String, dynamic> json) =>
_$ProductFromJson(json);
Map<String, dynamic> toJson() => _$ProductViewToJson(this);
file.g.dart
ProductView _$ProductViewFromJson(Map<String, dynamic> json) {
return
ProductView(
json['field1'] as int,
json['field2'] as String,
json['field3'] == null
? null
: DateTime.parse(json['field3'] as String),
);
}
Map<String, dynamic> _$ProjectViewToJson(ProductView instance) =>
<String, dynamic>{
'field1': instance.field1,
'field2': instance.field2,
'field3': instance.field3?.toIso8601String(),
};
decoding the json
var client = http.Client();
Map<String, String> headers = new HashMap();
headers['Accept'] = 'application/json';
headers['Content-Type'] = 'application/json';
headers['Authorization'] = 'Bearer $token';
var response = await client.get(url, headers: headers).timeout(_TIMEOUT);
var parsed = json.decode(response.body);
var view = ProductView.fromJson(parsed);

Getting null safety errors when tried to get autocomplete location of places in Flutter and display details on tapped place

I tried to migrate the no null safety code to null safety and I ended up with errors. I want to get autocomplete location of places in Flutter and display details on the tapped place.
Screenshots of errors:
The code:
main.dart
import 'package:flutter/material.dart';
import 'package:google_places_flutter/address_search.dart';
import 'package:google_places_flutter/place_service.dart';
import 'package:uuid/uuid.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Google Places Demo',
home: MyHomePage(title: 'Places Autocomplete 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 _controller = TextEditingController();
String? _streetNumber = '';
String? _street = '';
String? _city = '';
String? _zipCode = '';
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title!),
),
body: Container(
margin: EdgeInsets.only(left: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextField(
controller: _controller,
readOnly: true,
onTap: () async {
// generate a new token here
final sessionToken = Uuid().v4();
final Suggestion? result = await showSearch(
context: context,
delegate:AddressSearch(sessionToken),
);
// This will change the text displayed in the TextField
if (result != null) {
final placeDetails = await PlaceApiProvider(sessionToken)
.getPlaceDetailFromId(result.placeId);
setState(() {
_controller.text = result.description!;
_streetNumber = placeDetails.streetNumber;
_street = placeDetails.street;
_city = placeDetails.city;
_zipCode = placeDetails.zipCode;
});
}
},
decoration: InputDecoration(
icon: Container(
width: 10,
height: 10,
child: Icon(
Icons.home,
color: Colors.black,
),
),
hintText: "Enter address",
border: InputBorder.none,
contentPadding: EdgeInsets.only(left: 8.0, top: 16.0),
),
),
SizedBox(height: 20.0),
Text('Street Number: $_streetNumber'),
Text('Street: $_street'),
Text('City: $_city'),
Text('ZIP Code: $_zipCode'),
],
),
),
);
}
}
address_search.dart
import 'package:flutter/material.dart';
import 'package:google_places_flutter/place_service.dart';
class AddressSearch extends SearchDelegate<Suggestion?> {
AddressSearch(this.sessionToken) {
apiClient = PlaceApiProvider(sessionToken);
}
final sessionToken;
late PlaceApiProvider apiClient;
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
tooltip: 'Clear',
icon: Icon(Icons.clear),
onPressed: () {
query = '';
},
)
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
tooltip: 'Back',
icon: Icon(Icons.arrow_back),
onPressed: () {
close(context, null);
},
);
}
#override
Widget buildResults(BuildContext context) {
return Container();
}
#override
Widget buildSuggestions(BuildContext context) {
return FutureBuilder(
future: query == ""
? null
: apiClient.fetchSuggestions(
query, Localizations.localeOf(context).languageCode),
builder: (context, snapshot) => query == ''
? Container(
padding: EdgeInsets.all(16.0),
child: Text('Enter address'),
)
: snapshot.hasData
? ListView.builder(
itemBuilder: (context, index) =>
ListTile(
title:
Text((snapshot.data[index] as Suggestion).description!),
onTap: () {
close(context, snapshot.data[index] as Suggestion?);
},
),
itemCount: snapshot.data.length,
)
: Container(child: Text('Loading...')),
);
}
}
place_service.dart
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart';
class Place {
String? streetNumber;
String? street;
String? city;
String? zipCode;
Place({
this.streetNumber,
this.street,
this.city,
this.zipCode,
});
#override
String toString() {
return 'Place(streetNumber: $streetNumber, street: $street, city: $city, zipCode: $zipCode)';
}
}
class Suggestion {
final String? placeId;
final String? description;
Suggestion(this.placeId, this.description);
#override
String toString() {
return 'Suggestion(description: $description, placeId: $placeId)';
}
}
class PlaceApiProvider {
final client = Client();
PlaceApiProvider(this.sessionToken);
final sessionToken;
static final String androidKey = 'YOUR_API_KEY_HERE';
static final String iosKey = 'YOUR_API_KEY_HERE';
final apiKey = Platform.isAndroid ? androidKey : iosKey;
Future<List<Suggestion>?> fetchSuggestions(String input, String lang) async {
final request =
'https://maps.googleapis.com/maps/api/place/autocomplete/json?input=$input&key=$apiKey&sessiontoken=$sessionToken';
final response = await client.get(Uri.parse(request));
if (response.statusCode == 200) {
final result = json.decode(response.body);
if (result['status'] == 'OK') {
// compose suggestions in a list
return result['predictions']
.map<Suggestion>((p) => Suggestion(p['place_id'], p['description']))
.toList();
}
if (result['status'] == 'ZERO_RESULTS') {
return [];
}
throw Exception(result['error_message']);
} else {
throw Exception('Failed to fetch suggestion');
}
}
Future<Place> getPlaceDetailFromId(String? placeId) async {
final request =
'https://maps.googleapis.com/maps/api/place/details/json?place_id=$placeId&fields=address_component&key=$apiKey&sessiontoken=$sessionToken';
final response = await client.get(Uri.parse(request));
if (response.statusCode == 200) {
final result = json.decode(response.body);
if (result['status'] == 'OK') {
final components =
result['result']['address_components'] as List<dynamic>;
// build result
final place = Place();
components.forEach((c) {
final List type = c['types'];
if (type.contains('street_number')) {
place.streetNumber = c['long_name'];
}
if (type.contains('route')) {
place.street = c['long_name'];
}
if (type.contains('locality')) {
place.city = c['long_name'];
}
if (type.contains('postal_code')) {
place.zipCode = c['long_name'];
}
});
return place;
}
throw Exception(result['error_message']);
} else {
throw Exception('Failed to fetch suggestion');
}
}
}
The solution is probably this:
builder: (context, AsyncSnapshot<List<Suggestion>> snapshot)
instead of this:
builder: (context, snapshot)
then you can do something like:
List<Suggestion>? suggestions = snapshot.data;
if ( suggestions != null && suggestions.length > 0) {