I am using this multi-select flutter package. It already has contents to view chips, but I want to load contents from API to do that instead.
I already added a fetchData() function to download the data from the API. Now, how do I get the JSON data into the chips multi-select?
Here is my code:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:multiselect_formfield/multiselect_formfield.dart';
import 'package:multi_select_flutter/multi_select_flutter.dart';
import 'package:http/http.dart' as http;
import 'Includes/APILinks.dart';
void main() => runApp(Sample());
class Sample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List _myActivities;
String _myActivitiesResult;
final formKey = new GlobalKey<FormState>();
#override
void initState() {
super.initState();
_myActivities = [];
this.fetchData();
}
_saveForm() {
var form = formKey.currentState;
if (form.validate()) {
form.save();
setState(() {
_myActivitiesResult = _myActivities.toString();
});
}
}
fetchData() async{
var url = CategorySection;
var response = await http.get(url);
if(response.statusCode == 200){
var items = json.decode(response.body);
print(items);
setState(() {
_myActivities = items;
});
} else {
setState(() {
_myActivities = [];
});
}
}
#override
Widget build(BuildContext context) {
final double maxWidth = MediaQuery.of(context).size.width;
final double maxHeight = MediaQuery.of(context).size.height;
return Scaffold(
appBar: AppBar(
title: Text('MultiSelect Formfield Example'),
),
body: Center(
child: Form(
key: formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
height: maxHeight/2,
width: maxWidth,
padding: EdgeInsets.all(16),
child: getListView(),
),
Container(
padding: EdgeInsets.all(8),
child: RaisedButton(
child: Text('Save'),
onPressed: _saveForm,
),
),
Container(
padding: EdgeInsets.all(16),
child: Text(_myActivitiesResult),
)
],
),
),
),
);
}
Widget getListView() {
return ListView.builder(
itemCount: _myActivities.length,
itemBuilder: (context, index){
return cardView(_myActivities[index]);
},
);
}
Widget cardView(item) {
var fullName = item;
return MultiSelectDialogField(
items: _myActivities,
title: Text("Animals"),
selectedColor: Colors.blue,
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.all(Radius.circular(40)),
border: Border.all(
color: Colors.blue,
width: 2,
),
),
buttonIcon: Icon(
Icons.pets,
color: Colors.blue,
),
buttonText: Text(
"Favorite Animals",
style: TextStyle(
color: Colors.blue[800],
fontSize: 16,
),
),
onConfirm: (results) {
_myActivities = results;
},
);
}
}
You can use a Future function with the return type that you want, in that case it will be Future<List<MultiSelectItem>>, then you would use async and await, it will be something like that:
Future<List<Item>> fetchItems(BuildContext context) async {
http.Response response = await http.get(
Uri.parse('your link for ur api'),
//you can ignore that part
headers: <String, String>{
'Authorization':
'Token ${Provider.of<Token>(context, listen: false).token}'
});
//here you turn the json to a <String, dynamic> map
var data = jsonDecode(response.body);
List<Item> result = [];
for (var item in data) {
//use your factory if you wanna to parse the data the way you want it
result.add(Item.fromJson(item));
}
//that should be your disered list
return result;
}
The FilterChip class provides a multiple select chip. Using FutureBuilder we can fetch future data and build the chips list. We can also call the API first, and then map the results with the filter chips.
Here is an example of a FilterChip, where chips are populated from an API using FutureBuilder:
import 'dart:convert';
import 'package:filterchip_sample/album.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'FilterChip Sample',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'FilterChip Sample'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool favorite = false;
final List<int> _filters = <int>[];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
children: <Widget>[
FutureBuilder<List<Album>>(
future: _fetchAlbums(),
builder:
(BuildContext context, AsyncSnapshot<List<Album>> snapshot) {
Widget result;
if (snapshot.hasData) {
result = Wrap(
spacing: 5.0,
children: snapshot.data!.map((Album album) {
return FilterChip(
label: Text(album.title),
selected: _filters.contains(album.id),
onSelected: (bool value) {
setState(() {
if (value) {
if (!_filters.contains(album.id)) {
_filters.add(album.id);
}
} else {
_filters.removeWhere((int id) {
return id == album.id;
});
}
});
},
);
}).toList(),
);
} else if (snapshot.hasError) {
result = Text('Error: ${snapshot.error}');
} else {
result = const Text('Awaiting result...');
}
return result;
},
),
],
),
),
);
}
Future<List<Album>>? _fetchAlbums() async {
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/'));
if (response.statusCode == 200) {
var json = jsonDecode(response.body);
var albums = List<Album>.from(json.map((i) => Album.fromJson(i)));
return albums;
} else {
throw Exception('Failed to get albums');
}
}
}
Related
My code is the file name is interface.dart. I'm calling the interface.dart from the main.dart
I'm getting a permission denied error when try to access the contacts in the emulator
I added the permission_handler dependency in the pubspec.yaml
Then added the permissions in the AndroidManifest.xml for both read and write
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:contacts_service/contacts_service.dart';
import 'package:permission_handler/permission_handler.dart';
import 'dart:io';
import 'dart:convert';
import 'package:url_launcher/url_launcher.dart';
import 'package:path_provider/path_provider.dart';
class Interface extends StatelessWidget {
const Interface({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('pAM'),
),
body: const ContactSelector(),
);
}
}
class ContactSelector extends StatefulWidget {
const ContactSelector({super.key});
#override
_ContactSelectorState createState() => _ContactSelectorState();
}
class _ContactSelectorState extends State<ContactSelector> {
var status = Permission.contacts.status;
Contact _selectedContact = Contact();
late bool _isTrue;
#override
void initState() {
super.initState();
_readJson();
}
_selectContact() async {
List<Contact> contact =
await ContactsService.getContacts(withThumbnails: false);
setState(() {
_selectedContact = contact as Contact;
});
_saveContactToFile(_selectedContact);
}
_saveContactToFile(Contact contact) async {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/selected_contact.txt');
if (!(await file.exists())) {
file.create();
}
file.writeAsString(jsonEncode(contact.toMap()));
}
_readJson() async {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/true.json');
if (!(await file.exists())) {
file.createSync();
file.writeAsStringSync('{"isTrue":true}');
}
final content = jsonDecode(await file.readAsString());
setState(() {
_isTrue = content['isTrue'];
});
}
_promptMessage() {
if (_isTrue) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Select a message'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
InkWell(
child: const Text('How are you?'),
onTap: () {
_sendMessage('How are you?');
Navigator.of(context).pop();
}),
InkWell(
child: const Text('Did you have your lunch ?'),
onTap: () {
_sendMessage('Did you have your lunch ?');
Navigator.of(context).pop();
}),
InkWell(
child: const Text("What's for dinner?"),
onTap: () {
_sendMessage("What's for dinner?");
Navigator.of(context).pop();
}),
],
),
),
);
},
);
}
}
String? encodeQueryParameters(Map<String, String> params) {
return params.entries
.map((e) =>
'${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}')
.join('&');
}
_sendMessage(String message) async {
String phoneNumber = _selectedContact.phones.toString();
Uri uri = Uri(
scheme: 'sms',
path: phoneNumber,
query: encodeQueryParameters(<String, String>{
'body': 'Welcome to pAM',
}),
);
if (await canLaunchUrl(uri)) {
await canLaunchUrl(uri);
} else {
throw 'Could not send SMS';
}
}
#override
Widget build(BuildContext context) {
return MediaQuery(
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window),
child: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (_selectedContact != null)
Text(_selectedContact.displayName ?? 'No contact selected')
else
const Text('No contact selected'),
ElevatedButton(
onPressed: _selectContact,
child: const Text('Select Contact'),
),
ElevatedButton(
onPressed: _promptMessage,
child: const Text('Prompt Message'),
),
],
),
),
));
}
}
You are facing this issues because you haven't asked for the permission yet, refer the code below:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:contacts_service/contacts_service.dart';
import 'package:permission_handler/permission_handler.dart';
import 'dart:io';
import 'dart:convert';
import 'package:url_launcher/url_launcher.dart';
import 'package:path_provider/path_provider.dart';
class Interface extends StatelessWidget {
const Interface({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('pAM'),
),
body: const ContactSelector(),
);
}
}
class ContactSelector extends StatefulWidget {
const ContactSelector({super.key});
#override
_ContactSelectorState createState() => _ContactSelectorState();
}
class _ContactSelectorState extends State<ContactSelector> {
var status = Permission.contacts.status;
Contact _selectedContact = Contact();
late bool _isTrue;
#override
void initState() {
_readJson();
super.initState();
}
_selectContact() async {
if (await Permission.contacts.request().isGranted) {
List<Contact> contact =
await ContactsService.getContacts(withThumbnails: false);
setState(() {
_selectedContact = contact as Contact;
});
_saveContactToFile(_selectedContact);
}
}
_saveContactToFile(Contact contact) async {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/selected_contact.txt');
if (!(await file.exists())) {
file.create();
}
file.writeAsString(jsonEncode(contact.toMap()));
}
_readJson() async {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/true.json');
if (!(await file.exists())) {
file.createSync();
file.writeAsStringSync('{"isTrue":true}');
}
final content = jsonDecode(await file.readAsString());
setState(() {
_isTrue = content['isTrue'];
});
}
_promptMessage() {
if (_isTrue) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Select a message'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
InkWell(
child: const Text('How are you?'),
onTap: () {
_sendMessage('How are you?');
Navigator.of(context).pop();
}),
InkWell(
child: const Text('Did you have your lunch ?'),
onTap: () {
_sendMessage('Did you have your lunch ?');
Navigator.of(context).pop();
}),
InkWell(
child: const Text("What's for dinner?"),
onTap: () {
_sendMessage("What's for dinner?");
Navigator.of(context).pop();
}),
],
),
),
);
},
);
}
}
String? encodeQueryParameters(Map<String, String> params) {
return params.entries
.map((e) =>
'${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}')
.join('&');
}
_sendMessage(String message) async {
String phoneNumber = _selectedContact.phones.toString();
Uri uri = Uri(
scheme: 'sms',
path: phoneNumber,
query: encodeQueryParameters(<String, String>{
'body': 'Welcome to pAM',
}),
);
if (await canLaunchUrl(uri)) {
await canLaunchUrl(uri);
} else {
throw 'Could not send SMS';
}
}
#override
Widget build(BuildContext context) {
return MediaQuery(
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window),
child: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (_selectedContact != null)
Text(_selectedContact.displayName ?? 'No contact selected')
else
const Text('No contact selected'),
ElevatedButton(
onPressed: _selectContact,
child: const Text('Select Contact'),
),
ElevatedButton(
onPressed: _promptMessage,
child: const Text('Prompt Message'),
),
],
),
),
));
}
}
Check the permission status first as this:-
final status = Permission.contacts.request()
if(status.isGrantet){
// permission has granted now save the contact here
}
Refer this link for more details.
I'm creating a quiz app using Flutter & Firebase. I've fetched questions & options which don't contain images using Firebase, but I'm not able to fetch questions that contain an image in them.
This is a screenshot of the question, which doesn't have an image, I've fetched in the app:
Question with image is like shown below in excel format:
All these data except images are fetched from JSON file imported in Realtime Database in Firebase.
Below is the code where questions are fetched from Realtime database in Firebase:
import 'package:http/http.dart' as http;
import './question_model.dart';
import 'dart:convert';
import '../test.dart';
class DBconnect {
final url = Uri.parse(
'https://rto1-798fc-default-rtdb.firebaseio.com/questions.json');
Future<List<Question>> fetchQuestions() async {
return http.get(url).then((response) {
var data = json.decode(response.body) as Map<String, dynamic>;
List<Question> newQuestions = [];
data.forEach((key, value) {
var newQuestion = Question(
id: key,
title: value['title'],
options: Map.castFrom(value['options']),
);
newQuestions.add(newQuestion);
newQuestions.shuffle();
});
return newQuestions;
});
}
}
Below is the question model:
class Question {
final String id;
final String title;
final Map<String, bool> options;
Question({
required this.id,
required this.title,
required this.options,
});
#override
String toString() {
return 'Question(id: $id, title: $title, options: $options)';
}
}
Below is the question widget:
import 'package:flutter/material.dart';
import '../constants.dart';
class QuestionWidget extends StatelessWidget {
const QuestionWidget(
{Key? key,
required this.question,
required this.indexAction,
required this.totalQuestions})
: super(key: key);
final String question;
final int indexAction;
final int totalQuestions;
#override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.centerLeft,
child: Text(
'Question ${indexAction + 1}/20: $question',
style: const TextStyle(
fontSize: 24.0,
color: neutral,
),
),
);
}
}
And this is the main page:
import 'package:flutter/material.dart';
import '../constants.dart';
import '../models/question_model.dart';
import '../widgets/question_widget.dart';
import '../widgets/next_button.dart';
import '../widgets/option_card.dart';
import '../widgets/result_box.dart';
import '../models/db_connect.dart';
class TestScreen extends StatefulWidget {
const TestScreen({Key? key}) : super(key: key);
#override
State<TestScreen> createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen> {
var db = DBconnect();
late Future _questions;
Future<List<Question>> getData() async {
return db.fetchQuestions();
}
#override
void initState() {
_questions = getData();
super.initState();
}
int index = 0;
int score = 0;
bool isPressed = false;
bool isAlreadySelected = false;
void nextQuestion(int questionLength) {
if (index == 19 || score == 12) {
showDialog(
context: context,
barrierDismissible: false,
builder: (ctx) => ResultBox(
result: score,
questionLength: questionLength,
));
} else {
if (isPressed) {
setState(() {
index++;
isPressed = false;
isAlreadySelected = false;
});
} else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: const Text('Please select any option'),
behavior: SnackBarBehavior.floating,
margin: EdgeInsets.symmetric(vertical: 20.0),
));
}
}
}
void checkAnswerAndUpdate(bool value) {
if (isAlreadySelected) {
return;
} else {
if (value == true) {
score++;
setState(() {
isPressed = true;
isAlreadySelected = false;
});
} else if (value == false) {
setState(() {
isPressed = true;
isAlreadySelected = false;
});
}
}
}
void startOver() {
setState(() {
Text('You have already attempted the LL Test');
});
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _questions as Future<List<Question>>,
builder: (ctx, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return Center(
child: Text('${snapshot.error}'),
);
} else if (snapshot.hasData) {
var extractedData = snapshot.data as List<Question>;
return Scaffold(
backgroundColor: background,
appBar: AppBar(
title: const Text('LL Test'),
backgroundColor: background,
shadowColor: Colors.transparent,
actions: [
Padding(
padding: const EdgeInsets.all(18.0),
child: Text(
'Score: $score',
style: TextStyle(fontSize: 18.0),
),
)
],
),
body: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: Column(
children: [
QuestionWidget(
question: extractedData[index].title,
indexAction: index,
totalQuestions: extractedData.length,
),
const Divider(
color: neutral,
),
const SizedBox(height: 25.0),
for (int i = 0;
i < extractedData[index].options.length;
i++)
GestureDetector(
onTap: () => checkAnswerAndUpdate(
extractedData[index].options.values.toList()[i]),
child: OptionCard(
option: extractedData[index].options.keys.toList()[i],
color: isPressed
? extractedData[index]
.options
.values
.toList()[i] ==
true
? correct
: incorrect
: neutral,
),
),
],
),
),
floatingActionButton: GestureDetector(
onTap: () => nextQuestion(extractedData.length),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10.0),
child: NextButton(),
),
),
floatingActionButtonLocation:
FloatingActionButtonLocation.centerFloat,
);
}
} else {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(),
SizedBox(height: 20.0),
Text(
'Please Wait While Questions Are Loading..',
style: TextStyle(
backgroundColor: Color.fromARGB(255, 4, 82, 6),
color: neutral),
),
],
),
);
}
return const Center(
child: Text('NoData'),
);
},
);
}
}
I'm fetching images from https://pixabay.com/api/docs/ this web-page.
I'm trying to save that image with onTap() {} with Shared Preferences package and set as background on previous page. I tried to make Shared preferences class seperate but it was showing errors. So pref.setString() method I did in ontap() {} and pref.getString() in my Center() widget with ternary operator to show that if image url is empty, write text, if it contains image url, show image. I tried to put it into setState() {} method but there are all red squiggles. How can I achieve this?
Thank you very much in advance.
Here is my code:
this is the page I'm trying to set background image:
import 'package:abcde/authentication_screen/pages/photos_page.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AfterAuth extends StatefulWidget {
AfterAuth({Key? key}) : super(key: key);
static const String pathId = 'Welcome Page';
#override
State<AfterAuth> createState() => _AfterAuthState();
}
class _AfterAuthState extends State<AfterAuth> {
String welcomeScreen = 'Welcome to the club';
#override
void initState() {
// TODO: implement initState
super.initState();
//final prefs = await SharedPreferences.getInstance();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Welcome'),
),
drawer: Drawer(
backgroundColor: Colors.white,
child: ListView(
padding: EdgeInsets.zero,
children: [
const DrawerHeader(
decoration: BoxDecoration(
color: Colors.lightBlueAccent,
),
child: Text('Welcome'),
),
ListTile(
title: const Text(
'Bonjour',
),
onTap: () {
setState(() {
welcomeScreen = 'Bonjour';
});
Navigator.pop(context);
},
),
ListTile(
title: const Text('Hello'),
onTap: () {
setState(() {
welcomeScreen = 'Hello';
});
Navigator.pop(context);
},
),
ListTile(
title: const Text('Guten Tag'),
onTap: () {
setState(() {
welcomeScreen = 'Guten Tag';
});
Navigator.pop(context);
},
),
ListTile(
title: const Text('Au Revoir'),
onTap: () {
setState(() {
welcomeScreen = 'Au Revoir';
});
Navigator.pop(context);
},
),
ListTile(
title: const Text('Chao Bambino'),
onTap: () {
setState(() {
welcomeScreen = 'Chao Bambino';
});
Navigator.pop(context);
},
),
],
),
),
body: Center(
child: address == ''
? Text(welcomeScreen)
: Image(
image: NetworkImage(address),
),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.lightBlue,
onPressed: () {
Navigator.pushNamed(context, PhotosPage.pathId);
},
child: const Icon(
Icons.add,
color: Colors.white,
),
),
);
}
String address = '';
internalMemory() async {
final prefs = await SharedPreferences.getInstance();
address = prefs.getString('urlAddress')!;
/* if(address!.isNotEmpty) {
isAddressEmpty = false;
}*/
return address;
}
}
this is the page where I fetch images from api and trying to save with Shared Preferences. actually not sure if it saves and not sure how to check it:
import 'package:flutter/material.dart';
import '../../services/photos_service.dart';
import 'package:shared_preferences/shared_preferences.dart';
class PhotosPage extends StatefulWidget {
const PhotosPage({Key? key}) : super(key: key);
static const String pathId = 'Photos page';
#override
State<PhotosPage> createState() => _PhotosPageState();
}
class _PhotosPageState extends State<PhotosPage> {
PhotosService photosService = PhotosService();
#override
void initState() {
super.initState();
photosService.getPhotos();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Photos'),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(children: [
_getProductTypeList(),
]),
),
);
}
Widget _buildListItem(
BuildContext context, AsyncSnapshot<dynamic> snapshot, int index) {
final photoItem = snapshot.data[index].previewURL;
print('photoItem is $photoItem');
return photoCard(context, photoItem);
}
Widget _buildList(BuildContext context, AsyncSnapshot<dynamic> snapshot) {
var values = snapshot.data;
return ListView.builder(
itemCount: snapshot.hasData ? snapshot.data.length : 0,
itemBuilder: (context, index) {
return _buildListItem(context, snapshot, index);
},
);
}
Widget _getProductTypeList() {
return Expanded(
child: FutureBuilder(
future: photosService.getPhotos(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: LinearProgressIndicator(),
);
}
return _buildList(context, snapshot);
},
),
);
}
}
Widget photoCard(BuildContext context, String url) {
return GestureDetector(
onTap: () async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('urlAddress', url);
const snackBar =
SnackBar(content: Text('You saved image'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
child: Card(
child: Image(
image: NetworkImage(url),
),
),
);
}
this is my service/model
import 'dart:convert';
import 'package:http/http.dart';
const apiKey = '26711456-bde74f403cb42e77029bc1678';
const appUrl = 'https://pixabay.com/api/';
class PhotosService {
Future getData(String url) async {
print('Calling url: $url');
final response = await get(Uri.parse(url));
if (response.statusCode == 200) {
return response.body;
} else {
print(response.statusCode);
}
}
String? query;
List<PhotosModel> dataList = [];
Future<List<PhotosModel>> getPhotos() async {
final photosData = await getData('$appUrl?key=$apiKey&q=$query');
var data = json.decode(photosData);
var items = data["hits"];
items.forEach((element) {
dataList.add(PhotosModel.fromJson(element));
});
print('this is photos data: $photosData');
return dataList;
}
}
class PhotosModel {
String previewURL;
PhotosModel({required this.previewURL});
factory PhotosModel.fromJson(Map<dynamic, dynamic> json) =>
_commentFromJson(json);
Map<dynamic, dynamic> toJson() => photosModelToJson(this);
}
PhotosModel _commentFromJson(Map<dynamic, dynamic> json) {
return PhotosModel(
previewURL: json['previewURL'],
);
}
Map<dynamic, dynamic> photosModelToJson(PhotosModel instance) =>
<dynamic, dynamic>{
'previewURL': instance.previewURL,
};
Call your function on initState to set the background on restart the app.
#override
void initState() {
// TODO: implement initState
super.initState();
internalMemory();
//final prefs = await SharedPreferences.getInstance();
}
add setstate to your internalMemory() function to set background
internalMemory() async {
final prefs = await SharedPreferences.getInstance();
address = await prefs.getString('urlAddress')!;
setState((){});
}
also, add the function below to set the background when you navigate back.
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.lightBlue,
onPressed: () async {
await Navigator.pushNamed(context, PhotosPage.pathId);
internalMemory();
},
child: const Icon(
Icons.add,
color: Colors.white,
),
),
I am trying to make a pokemon app. But I get this error:
"The getter 'pokemon' was called on null.
Receiver: null
Tried calling: pokemon"
I am using this API url for data "https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json"
And my Pokemon class is here:
class PokeHub {
List<Pokemon> pokemon;
PokeHub({this.pokemon});
PokeHub.fromJson(Map<String,dynamic> json) {
if (json['pokemon'] != null) {
pokemon = new List<Pokemon>();
json['pokemon'].forEach((items) {
pokemon.add(new Pokemon.fromJson(items));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.pokemon != null) {
data['pokemon'] = this.pokemon.map((items) => items.toJson()).toList();
}
return data;
}
}
class Pokemon {
int id;
String num;
String name;
String img;
List<String> type;
String height;
String weight;
String candy;
int candyCount;
String egg;
String spawnChance;
String avgSpawns;
String spawnTime;
List<double> multipliers;
List<String> weaknesses;
List<NextEvolution> nextEvolution;
Pokemon(
{this.id,
this.num,
this.name,
this.img,
this.type,
this.height,
this.weight,
this.candy,
this.candyCount,
this.egg,
this.spawnChance,
this.avgSpawns,
this.spawnTime,
this.multipliers,
this.weaknesses,
this.nextEvolution});
Pokemon.fromJson(Map<String, dynamic> json) {
id = json['id'];
num = json['num'];
name = json['name'];
img = json['img'];
type = json['type'].cast<String>();
height = json['height'];
weight = json['weight'];
candy = json['candy'];
candyCount = json['candy_count'];
egg = json['egg'];
spawnChance = json['spawn_chance'].toString();
avgSpawns = json['avg_spawns'].toString();
spawnTime = json['spawn_time'];
multipliers = json['multipliers']?.cast<double>();
weaknesses = json['weaknesses'].cast<String>();
if (json['next_evolution'] != null) {
nextEvolution = new List<NextEvolution>();
json['next_evolution'].forEach((v) {
nextEvolution.add(new NextEvolution.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['num'] = this.num;
data['name'] = this.name;
data['img'] = this.img;
data['type'] = this.type;
data['height'] = this.height;
data['weight'] = this.weight;
data['candy'] = this.candy;
data['candy_count'] = this.candyCount;
data['egg'] = this.egg;
data['spawn_chance'] = this.spawnChance;
data['avg_spawns'] = this.avgSpawns;
data['spawn_time'] = this.spawnTime;
data['multipliers'] = this.multipliers;
data['weaknesses'] = this.weaknesses;
if (this.nextEvolution != null) {
data['next_evolution'] =
this.nextEvolution.map((v) => v.toJson()).toList();
}
return data;
}
}
class NextEvolution {
String num;
String name;
NextEvolution({this.num, this.name});
NextEvolution.fromJson(Map<String, dynamic> json) {
num = json['num'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['num'] = this.num;
data['name'] = this.name;
return data;
}
And this is my main.dart file:
import 'package:flutter/material.dart';
import 'package:pokemon_flutter/screens/main_screen.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Poke App",
home: MainScreen(),
debugShowCheckedModeBanner: false,
);
}
}
And this is my main_screen.dart file:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:pokemon_flutter/models/pokemon.dart';
class MainScreen extends StatefulWidget {
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
var url =
"https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json";
PokeHub pokeHub;
#override
void initState() {
super.initState();
fetchData();
}
void fetchData() async {
var res = await http.get(url);
var decodedJson = jsonDecode(res.body);
pokeHub = PokeHub.fromJson(decodedJson);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Poke App"),
backgroundColor: Colors.cyan,
),
body: GridView.count(
crossAxisCount: 2,
children: pokeHub.pokemon.map((poke) => Card()).toList(),
),
drawer: Drawer(),
floatingActionButton: FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.cyan,
child: Icon(Icons.refresh),
),
);
}
}
It seems like all things are true thats why I can not recognized the fault. If you have a advice for this situation I'll be appreciated.
Edit: I am new here thats why sometimes my questions could be meanless.But please dont decrease my points. Stackoverflow not gonna accept my questions anymore. Please increase my points.
when I finished my code the aplication worked. Here is my new main_screen.dart file:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:pokemon_flutter/models/pokemon.dart';
import 'package:pokemon_flutter/screens/pokemon_detail_screen.dart';
class MainScreen extends StatefulWidget {
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
var url =
"https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json";
PokeHub pokeHub;
#override
void initState() {
super.initState();
fetchData();
}
var res;
void fetchData() async {
res= await http.get(url);
var decodedJson = jsonDecode(res.body);
pokeHub = PokeHub.fromJson(decodedJson);
print(pokeHub.toJson());
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Poke App"),
backgroundColor: Colors.cyan,
),
body: pokeHub == null
? Center(
child: CircularProgressIndicator(),
)
: GridView.count(
crossAxisCount: 2,
children: pokeHub.pokemon
.map((poke) => Padding(
padding: const EdgeInsets.all(2.0),
child: InkWell(
onTap: (){
Navigator.push(context, MaterialPageRoute(builder: (context)=>PokeDetail(
pokemon: poke,
)));
},
child: Hero(
tag: poke.img,
child: Card(
elevation: 3.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
height: 100.0,
width: 100.0,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(poke.img))),
),
Text(
poke.name,
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
)
],
),
),
),
),
))
.toList(),
),
drawer: Drawer(),
floatingActionButton: FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.cyan,
child: Icon(Icons.refresh),
),
);
}
}
I added if else statement and set state. I don't know how I solved this problem but it was solved.
I think this codes are worked:
void fetchData() async {
res= await http.get(url);
var decodedJson = jsonDecode(res.body);
pokeHub = PokeHub.fromJson(decodedJson);
print(pokeHub.toJson());
setState(() {});
}
body: pokeHub == null
? Center(
child: CircularProgressIndicator(),
)
: GridView.count(
When you call pokeHub.pokemon, pokeHub is still null so it can't return any value for pokemon getter.
I see that you are fetching data, but when your widget is built, this data (which is returned asynchronously) hasn't been returned yet. For this case, it will be a good choice using FutureBuilder. Something like this should work:
var res;
void fetchData() {
res = http.get(url).then((value){
var decodedJson = jsonDecode(res.body);
pokeHub = PokeHub.fromJson(decodedJson);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Poke App"),
backgroundColor: Colors.cyan,
),
body: FutureBuilder(
future: res,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.hasData)
return GridView.count(
crossAxisCount: 2,
children: pokeHub.pokemon.map((poke) => Card()).toList(),
),
drawer: Drawer(),
floatingActionButton: FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.cyan,
child: Icon(Icons.refresh),
);
},
),
);
}
This (kind of) uses the futurebuilder to build the widgets only once the data has been retrieved. More info: https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html
I'm trying to build a URL shortner using the following api: https://shrtco.de/docs/. I parsed the JSON file and tried to rebuild the listview. But after adding the url I'm getting the above error. The api seems to be working fine when I print it though. I don't know whats wrong. I'm a beginner in Flutter and Dart. Please help me.
class _homePageState extends State<homePage> {
getdata(String userUrl) async {
//JSON Parser
var url = 'https://api.shrtco.de/v2/shorten?url=$userUrl';
var respons = await http.get(url);
var result = jsonDecode(respons.body);
var shortlink = result['result']['short_link']; //dictionary parse
print(shortlink);
return shortlink;
}
Future<String> createAlertDialog(BuildContext context) {
//method for alertdialog
//promise to return string
TextEditingController customController =
TextEditingController(); //new texteditingc object
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Enter URL: "),
content: TextField(
controller: customController,
),
actions: [
MaterialButton(
elevation: 5.0,
child: Text("OK"),
onPressed: () {
if (customController.text != null &&
customController.text != "") {
var getShortlink = getdata(customController.text);
item.add(getShortlink);
}
setState(() {});
Navigator.of(context).pop();
},
)
],
);
});
}
#override
Widget build(BuildContext context) {
String temp;
return Scaffold(
appBar: AppBar(
title: Text("Shortie"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: item.length,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.link),
title: Text(item[index]),
subtitle: Text("data"),
);
//return new Text();
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
createAlertDialog(context).then((onValue) {
temp = onValue;
print(temp);
});
},
You can copy paste run full code below
Step 1: getdata return Future<String>
Step 2: onPressed need async await
Step 3: put getShortlink in Navigator.of(context).pop(getShortlink);
code snippet
Future<String> getdata(String userUrl) async {
...
onPressed: () async {
String getShortlink;
if (customController.text != null &&
customController.text != "") {
getShortlink = await getdata(customController.text);
item.add(getShortlink);
}
setState(() {});
Navigator.of(context).pop(getShortlink);
},
working demo
full code
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> item = [];
Future<String> getdata(String userUrl) async {
//JSON Parser
var url = 'https://api.shrtco.de/v2/shorten?url=$userUrl';
var respons = await http.get(url);
var result = jsonDecode(respons.body);
var shortlink = result['result']['short_link']; //dictionary parse
print(shortlink);
return shortlink;
}
Future<String> createAlertDialog(BuildContext context) {
//method for alertdialog
//promise to return string
TextEditingController customController =
TextEditingController(text: "example.org/very/long/link.html"); //new texteditingc object
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Enter URL: "),
content: TextField(
controller: customController,
),
actions: [
MaterialButton(
elevation: 5.0,
child: Text("OK"),
onPressed: () async {
String getShortlink;
if (customController.text != null &&
customController.text != "") {
getShortlink = await getdata(customController.text);
item.add(getShortlink);
}
setState(() {});
Navigator.of(context).pop(getShortlink);
},
)
],
);
});
}
#override
Widget build(BuildContext context) {
String temp;
return Scaffold(
appBar: AppBar(
title: Text("Shortie"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: item.length,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.link),
title: Text(item[index]),
subtitle: Text("data"),
);
//return new Text();
},
),
),
floatingActionButton: FloatingActionButton(onPressed: () {
createAlertDialog(context).then((onValue) {
temp = onValue;
print(temp);
});
}));
}
}
createAlertDialog(BuildContext context) doesn't return a Future<String>, it's returns Future<T>, dynamic in your case.
https://api.flutter.dev/flutter/material/showDialog.html