Flutter "A non-null String must be provided to a Text widget." - flutter

I am trying to get the data from an API and I get the data, but when I show it on the screen I get this error
Assertion failed: file:///home/builder/hotbuilder/packages/flutter/lib/src/widgets/text.dart:378:10
data != null.
I saw some examples, but I still don't understand how to solve it
This is main.dart
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:flutter_api_git/modelo/repo.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Demo',
home: Home(),
);
}
}
Future<All> fetchRepos() async {
final response =
await http.get(Uri.parse('https://api.github.com/users/IcaroOli/repos'));
if (response.statusCode == 200) {
print(response.body);
return All.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to fetch repos!');
}
}
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
late Future<All> futureRepo;
#override
void initState() {
super.initState();
futureRepo = fetchRepos();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('GitHub API!'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: FutureBuilder<All>(
future: futureRepo,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Repo> repos = <Repo>[];
for (int i = 0; i < snapshot.data!.repos.length; i++) {
repos.add(
Repo(
name: snapshot.data.repos[i].name,
description: snapshot.data!.repos[i].description,
htmlUrl: snapshot.data!.repos[i].htmlUrl,
stargazersCount: snapshot.data!.repos[i].stargazersCount,
),
);
}
return ListView(
children: repos
.map(
(r) => Card(
color: Colors.blue[300],
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
r.name,
style: const TextStyle(fontSize: 30.0),
),
Text(r.stargazersCount.toString()),
],
),
Text(
r.description,
style: const TextStyle(fontSize: 23.0),
),
Text(r.htmlUrl),
],
),
),
),
)
.toList(),
);
} else if (snapshot.hasError) {
return const Center(
child: Text('Error!'),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
),
);
}
}
This is repo.dart
class Repo {
String name;
String htmlUrl; // hmtl_url
int stargazersCount; //stargazers_count
String description;
Repo(
{required this.name,
required this.htmlUrl,
required this.stargazersCount,
required this.description});
factory Repo.fromJson(Map<String, dynamic> json) {
return Repo(
name: json['name'],
htmlUrl: json['html_url'],
stargazersCount: json['stargazers_count'],
description: json['description'],
);
}
}
class All {
List<Repo> repos;
All({required this.repos});
factory All.fromJson(List<dynamic> json) {
List<Repo> repos = <Repo>[];
repos = json.map((r) => Repo.fromJson(r)).toList();
return All(repos: repos);
}
}
class Repo {
String name;
String htmlUrl; // hmtl_url
int stargazersCount; //stargazers_count
String description;
Repo(
{required this.name,
required this.htmlUrl,
required this.stargazersCount,
required this.description});
factory Repo.fromJson(Map<String, dynamic> json) {
return Repo(
name: json['name'],
htmlUrl: json['html_url'],
stargazersCount: json['stargazers_count'],
description: json['description'],
);
}
}
class All {
List<Repo> repos;
All({required this.repos});
factory All.fromJson(List<dynamic> json) {
List<Repo> repos = <Repo>[];
repos = json.map((r) => Repo.fromJson(r)).toList();
return All(repos: repos);
}
}

This happens when you pass a null value to a text widget.
Try adding empty string if the value is null.
Text(r.name ?? ""),

One way to make sure they are never null is to provide fallback values in the factory of Repo, for example an empty string, like this:
factory Repo.fromJson(Map<String, dynamic> json) {
return Repo(
name: json['name'] ?? "",
htmlUrl: json['html_url'] ?? "",
stargazersCount: json['stargazers_count'] ?? 0,
description: json['description'] ?? "",
);
}

Related

IExpected a value of type 'String', but got one of type 'Null'

I am trying to fetch data Using Github API and display it in flutter app but in FutureBuilder snapshot.hasData shows its null and executes snapshot.hasError.
I want to display name of repositories from github in a ListView
Can you u help to understand and correct the error.
Here is the code :
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class Repo {
String name;
String htmlUrl;
//int stargazersCount;
String description;
Repo(
{required this.name,
required this.htmlUrl,
//required this.stargazersCount,
required this.description}
);
factory Repo.fromJson(Map<String, dynamic> json) {
return Repo(
name: json['name'],
htmlUrl: json['html_url'],
//stargazersCount: json['stargazers_count'],
description: json['description'],
);
}
}
class All {
List<Repo> repos;
All({required this.repos});
factory All.fromJson(List<dynamic> json) {
// ignore: prefer_collection_literals
List<Repo> repos = List<Repo>.empty(growable: true);
repos = json.map((r) => Repo.fromJson(r)).toList();
print(repos);
return All(repos: repos);
}
}
Future<All> fetchRepos() async {
final response =
await http.get(Uri.parse('https://api.github.com/users/freeCodeCamp/repos'));
if (response.statusCode == 200) {
//print(response.body);
return All.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to Fetch repos!');
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late Future<All> futureRepo;
#override
void initState() {
super.initState();
futureRepo=fetchRepos();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Github Repo List'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: FutureBuilder<All>(
future: futureRepo,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Repo> repos = List<Repo>.empty(growable: true);
for (int i = 0; i < snapshot.data!.repos.length; i++) {
repos.add(
Repo(
name: snapshot.data!.repos[i].name,
htmlUrl: snapshot.data!.repos[i].htmlUrl,
// stargazersCount:
// snapshot.data!.repos[i].stargazersCount,
description: snapshot.data!.repos[i].htmlUrl,
),
);
}
return ListView(
children: repos.map((r) => Card(
child: Column(
children: [
Text(r.name),
Text(r.description),
Text(r.htmlUrl),
//Text(r.stargazersCount.toString())
],
),
)).toList(),
);
} else if (snapshot.hasError) {
print(snapshot.error);
return const Center(
child: Text('Error'),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
)
);
}
}
while executing snapshot.error it displays the bellow error:
Expected a value of type 'String', but got one of type 'Null'
The Repo data model is built wrong. They should use Null safe
class Repo {
String? name;
String? htmlUrl;
//int stargazersCount;
String? description;
Repo(this.name, this.htmlUrl, this.description);
factory Repo.fromJson(Map<String, dynamic> json) {
return Repo(
json['name'],
json['html_url'],
//stargazersCount: json['stargazers_count'],
json['description'],
);
}
}
return ListView(
children: repos
.map((r) => Card(
child: Column(
children: [
Text(r.name ?? ''),
Text(r.description ?? ''),
Text(r.htmlUrl ?? ''),
//Text(r.stargazersCount.toString())
],
),
))
.toList(),
);

Fetch data from API, but the list is empty, it used to work 30 mins ago

Fetching from the api should be right, but it's not working since my list of "_movies" is empty. It was good looking application 2 hours ago and i dont know what i changed to do this.
It returns either nothing when itemCount:_movies.length or error "invalid value: valid value range is empty: 0. I'm stuck on this.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:task/models/movies.dart';
import 'package:http/http.dart' as http;
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<Movie> _movies = <Movie>[];
var moviesUrl =
'https://raw.githubusercontent.com/FEND16/movie-json-data/master/json/movies-coming-soon.json';
Future<List<Movie>> getMovies() async {
http.Response res = await http.get(Uri.parse(moviesUrl));
try {
if (res.statusCode == 200) {
List<dynamic> movies = json.decode(res.body);
return movies.map((e) => Movie.fromJson(e)).toList();
} else {
return <Movie>[];
}
} catch (e) {
// print(e);
return <Movie>[];
}
}
#override
void initState() {
getMovies().then((value) {
setState(() {
_movies.addAll(value);
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Movies"),
),
body: ListView.builder(
itemCount: _movies.length,
itemBuilder: (context, index) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
_movies[index].title,
style:
TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
),
Text(
_movies[index].genres.toString(),
style: TextStyle(
fontSize: 16,
),
),
],
),
),
);
}),
);
}
}
seems like _movies.lenght is 0, but somehow it worked right 2 hours ago and i didnt change a thing
class Movie {
String id;
String title;
String year;
List genres;
// List ratings;
String poster; //image
// String contentRating;
String duration;
// DateTime releaseDate;
// int averageRating;
String originalTitle;
String storyline;
List actors;
// String imdbRating;
String posterurl; //image
Movie({
required this.id,
required this.title,
required this.year,
required this.genres,
// required this.ratings,
required this.poster,
// required this.contentRating,
required this.duration,
// required this.releaseDate,
// required this.averageRating,
required this.originalTitle,
required this.storyline,
required this.actors,
// required this.imdbRating,
required this.posterurl,
});
factory Movie.fromJson(Map<String, dynamic> json) {
return Movie(
id: json["id"],
title: json["title"],
year: json["year"],
genres: json["genres"],
// ratings: json["ratnigs"],
poster: json["poster"],
// contentRating: json["contentRating"],
duration: json["duration"],
// releaseDate: json["releaseDate"],
// averageRating: json["averageRating"],
originalTitle: json["originalTitle"],
storyline: json["storyline"],
actors: json["actors"],
// imdbRating: json["imdbRating"],
posterurl: json["posterurl"]);
}
}
I believe the error must be on this line:
getMovies().then((value) {
setState(() {
_movies.addAll(value);
});
});
I think dart is confused about rebuilding the _movies variable because you are modifying it instead of reassigning it. If I am right, the solution is as simple as reassigning _movies:
getMovies().then((value) {
setState(() {
_movies = [..._movies, ...value]
});
});

Parsing Nested JSON with Flutter (Dart)

This is the JSON Response I'm getting. I want to Parse the text which says "url" (With. I want to Get this Text)
{
"data": [
{
"id": 1,
"attributes": {
"Title": "My Story",
"Story": "My story is about my life",
"Image": {
"data": {
"id": 1,
"attributes": {
"name": "lifeImage.jpeg",
"alternativeText": "lifeImage.jpeg",
"caption": "lifeImage.jpeg",
"url": "/uploads/lifeImage_0e9293ee8d.jpeg", <-- I want to Get this Text
"previewUrl": null,
"provider": "local"
}
}
}
}
}
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 3
}
}
}
I easily parsed the Title, Story with the Below Dart File.
But I'm not sure how can I parse the URL text (One with arrow marks says "<-- I want to Get this Text"). Since it's nested one I don't know how to do that. Please help me with this. Thanks
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
import 'StoryPage.dart';
void main() => runApp(App());
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My Stories',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const Homepage(),
);
}
}
class Homepage extends StatefulWidget {
const Homepage({Key? key}) : super(key: key);
#override
_HomepageState createState() => _HomepageState();
}
class _HomepageState extends State<Homepage> {
Future<List<Story>> _getStories() async {
var response = await http.get(Uri.parse(
'https://exampleapi.com/api/stories/?populate=Image'));
if (response.statusCode == 200) {
Map responseData = jsonDecode(response.body);
List StoriesList = responseData["data"];
List<Story> stories = [];
for (var storyMap in StoriesList) {
stories.add(Story.fromJson(storyMap["attributes"]));
}
return stories;
} else {
throw Exception('Failed to load stories');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('My Stories'),
),
body: Container(
child: FutureBuilder(
future: _getStories(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return InkWell(
child: Card(
child: Padding(
padding: const EdgeInsets.only(
top: 32.0, bottom: 32.0, left: 16.0, right: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
snapshot.data[index].title,
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new StoryPage(
snapshot.data[index],
title: snapshot.data[index].title,
body: snapshot.data[index].body,
)));
},
);
},
);
}
},
),
),
);
}
}
class Story {
final String title;
final String body;
Story({required this.title, required this.body});
factory Story.fromJson(Map<String, dynamic> json) {
return Story(
title: json['Title'],
body: json['Story'],
);
}
}
You can simply parse them like this:
final url = json['image']?['data']?['attributes']?['url'];
here we're using question marks (?) in between, because we're not sure that each element is not null, for example, the data under image may be null, so by using question marks, we're staying safe from null exceptions.
I took #Adnan approach and modified it little.
final ImageURL = json['Image']?['data']?['attributes']?['url'] ?? ''
Thanks to GitHub Co-Pilot.
I suggest using this website to generate dart or any other language object from json.
you just need to covert it to null safety.
here a example:
class AnswerResponse {
AnswerResponse({
required this.id,
required this.description,
required this.isAccepted,
required this.isMine,
required this.media,
required this.caseId,
required this.voteUp,
required this.voteDown,
required this.votes,
required this.user,
required this.comment,
required this.createdAt,
});
factory AnswerResponse.fromJson(final String str) => AnswerResponse.fromMap(json.decode(str));
factory AnswerResponse.fromMap(final Map<String, dynamic> json) => AnswerResponse(
id: json["id"],
description: json["description"],
isAccepted: json["isAccepted"],
isMine: json["isMine"],
media: json["media"] == null ? null : List<MediaResponse>.from(json["media"].map((final dynamic x) => MediaResponse.fromMap(x))),
caseId: json["caseId"],
voteUp: json["voteUp"],
voteDown: json["voteDown"],
votes: json["votes"],
user: json["user"] == null ? null : ProfileResponse.fromMap(json["user"]),
comment: json["comment"] == null ? null : List<CommentResponse>.from(json["comment"].map((final dynamic x) => CommentResponse.fromMap(x))),
createdAt: json["createdAt"],
);
final int? id;
final int? caseId;
final int? votes;
final bool? isAccepted;
final bool? isMine;
final bool? voteUp;
final bool? voteDown;
final String? description;
final String? createdAt;
final ProfileResponse? user;
final List<MediaResponse>? media;
final List<CommentResponse>? comment;
}
and to convert json string to dart object:
var data = AnswerResponse.fromMap(jsonString)

parsing data in model class in dart _type error?

I am learning Dart and Flutter. Now I am tasting JSON as a persistence method. I get lots of errors, all concerning Types and stuff. This is the latest error I have experienced: _TypeError (type 'List' is not a subtype of type 'Map')
_TypeError (type 'String' is not a subtype of type 'Map')
static Resource<List<ProductImage>> get all {
return Resource(
url: Constants.HEADLINE_NEWS_URL,
parse: (response) {
String jsonProduct = response.body;
final jsonResponse = json.decode(jsonProduct);
Product product = new Product.fromJson(jsonResponse);
return product.images.toList();
//return list.map((model) => NewsArticle.fromJson(model));
}
);
}
My Model :
class Product {
final String id;
final List<ProductImage> images;
Product({this.id, this.images});
factory Product.fromJson(Map<String, dynamic> parsedJson){
var list = parsedJson['IDEPELTION'] as List;
print(list.runtimeType);
List<ProductImage> imagesList = list.map((i) => ProductImage.fromJson(i)).toList();
return Product(
id: parsedJson['DATAS'],
images: imagesList
);
}
}
class ProductImage {
final String itemName;
final String iCategory;
// bool isCheck;
ProductImage({this.itemName, this.iCategory});
factory ProductImage.fromJson(Map<String, dynamic> parsedJson){
return ProductImage(
itemName:parsedJson['ITEM_NAME'],
iCategory:parsedJson['CATEGORY'],
//isCheck:false
);
}
}
this is my sample json return the list data to get all method
{"DATAS":"1","IDEPELTION":[{"ITEM_NAME":TRUEMETRIX ,"CATEGORY":"MOUTHPIECE"},{"ITEM_NAME":MULTISTIX 10SG 2161,"CATEGORY":"MOUTHPIECE"}]}
You can copy paste run full code below
You can see related Product class in full code and parse with product = productFromJson(jsonString);
code snippet
String jsonString = '''
{"DATAS":"1",
"IDEPELTION":
[{"ITEM_NAME":"TRUEMETRIX" ,
"CATEGORY":"MOUTHPIECE"},
{"ITEM_NAME":"MULTISTIX 10SG 2161",
"CATEGORY":"MOUTHPIECE"}]}
''';
product = productFromJson(jsonString);
working demo
full code
import 'package:flutter/material.dart';
import 'dart:convert';
Product productFromJson(String str) => Product.fromJson(json.decode(str));
String productToJson(Product data) => json.encode(data.toJson());
class Product {
String datas;
List<Idepeltion> idepeltion;
Product({
this.datas,
this.idepeltion,
});
factory Product.fromJson(Map<String, dynamic> json) => Product(
datas: json["DATAS"],
idepeltion: List<Idepeltion>.from(
json["IDEPELTION"].map((x) => Idepeltion.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"DATAS": datas,
"IDEPELTION": List<dynamic>.from(idepeltion.map((x) => x.toJson())),
};
}
class Idepeltion {
String itemName;
String category;
Idepeltion({
this.itemName,
this.category,
});
factory Idepeltion.fromJson(Map<String, dynamic> json) => Idepeltion(
itemName: json["ITEM_NAME"],
category: json["CATEGORY"],
);
Map<String, dynamic> toJson() => {
"ITEM_NAME": itemName,
"CATEGORY": category,
};
}
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> {
int _counter = 0;
Product product;
void _incrementCounter() {
String jsonString = '''
{"DATAS":"1",
"IDEPELTION":
[{"ITEM_NAME":"TRUEMETRIX" ,
"CATEGORY":"MOUTHPIECE"},
{"ITEM_NAME":"MULTISTIX 10SG 2161",
"CATEGORY":"MOUTHPIECE"}]}
''';
product = productFromJson(jsonString);
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
product == null
? Container()
: Expanded(
child: ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: product.idepeltion.length,
itemBuilder: (BuildContext context, int index) {
return Container(
child: Center(
child: Text(
'${product.idepeltion[index].category} ${product.idepeltion[index].itemName}')),
);
}),
),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
Change:
String jsonProduct = response.body;
Into this:
Map<String,dynamic> jsonProduct = response.body;
Since the response is of type Map

How to get the specific data through api by using flutter_bloc

I am beginner in flutter and working on fetching the specific data by using flutter_bloc package. I have successfully fetch the api data by using flutter_bloc in HomePage but how do i fetch the more specific data.For example in Home Page it fetch the data when i open the app and there is a button at the bottom which moves to new screen that is a Settings Screen which has Two radio buttons and one Raised Button named as Save.When i select any of the radiobutton and click on save button it should moves back to the homepage and calls the api and update the data which was already fetched in homepage. Below is the dart code and bloc code, it will be lengthy but hope you understand my code
Main.dart
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<PrayerBloc>(
create: (BuildContext context) => PrayerBloc(repository: PrayerRepositoryImpl()),
),
BlocProvider<MethodBloc>(
create: (BuildContext context) => MethodBloc(methodRepository: MethodRepositoryImpl()),
),
],
child: HomePage(),
);
HomePage.dart
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
PrayerBloc prayerBloc;
#override
void initState() {
super.initState();
prayerBloc = BlocProvider.of<PrayerBloc>(context);
prayerBloc.add(FetchPrayerEvent());
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(
builder: (context) {
return Material(
child: Scaffold(
appBar: AppBar(
title: Text("Prayer API"),
),
body: Container(
child: BlocListener<PrayerBloc, PrayerState>(
listener: (context, state) {
if (state is PrayerErrorState) {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text(state.message),
),
);
}
},
child: BlocBuilder<PrayerBloc, PrayerState>(
builder: (context, state) {
if (state is InitialPrayerState) {
return buildLoading();
} else if (state is PrayerLoadingState) {
return buildLoading();
} else if (state is PrayerLoadedState) {
return buildArticleList(state.item);
} else if (state is PrayerErrorState) {
return buildErrorUi(state.message);
}
},
),
),
),
),
);
},
),
);
}
Widget buildLoading() {
return Center(
child: CircularProgressIndicator(),
);
}
Widget buildErrorUi(String message) {
return Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
message,
style: TextStyle(color: Colors.red),
),
),
);
}
Widget buildArticleList(List<Item> item) {
return ListView.builder(
itemCount: item == null ? 0 : item.length,
itemBuilder: (BuildContext ctx, int pos) {
return new Container(
child: new Center(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: new Container(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10.0),
),
Row(
children: <Widget>[
Text("Fajr"),
Padding(
padding: EdgeInsets.only(left: 50.0),
),
Text(item[pos].fajr),
],
),
Row(
children: <Widget>[
Text("Dhuhr"),
Padding(
padding: EdgeInsets.only(left: 30.0),
),
Text(item[pos].dhuhr),
],
),
Builder(
builder: (context)=>
RaisedButton(
onPressed: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SettingsPage()),
);
},
),
)
],
),
),
),
)
],
),
),
);
},
);
}
Prayer_bloc.dart
class PrayerBloc extends Bloc<PrayerEvent, PrayerState> {
PrayerRepository repository;
PrayerBloc({#required this.repository});
#override
PrayerState get initialState => InitialPrayerState();
#override
Stream<PrayerState> mapEventToState(
PrayerEvent event,
) async* {
if (event is FetchPrayerEvent) {
yield PrayerLoadingState();
try {
List<Item> item = await repository.getItem();
yield PrayerLoadedState(item: item);
} catch (e) {
yield PrayerErrorState(message: e.toString());
}
}
}
}
PrayerEvent.dart
abstract class PrayerEvent extends Equatable {}
class FetchPrayerEvent extends PrayerEvent {
#override
// TODO: implement props
List<Object> get props => null;
}
PrayerState.dart
abstract class PrayerState extends Equatable {
const PrayerState();
}
class InitialPrayerState extends PrayerState {
#override
List<Object> get props => [];
}
class PrayerLoadingState extends PrayerState {
#override
List<Object> get props => [];
}
class PrayerLoadedState extends PrayerState {
List<Item> item;
PrayerLoadedState({#required this.item});
#override
List<Object> get props => null;
}
class PrayerErrorState extends PrayerState {
String message;
PrayerErrorState({#required this.message});
#override
List<Object> get props => [message];
}
PrayerRepository.dart
abstract class PrayerRepository {
Future<List<Item>> getItem();
}
class PrayerRepositoryImpl implements PrayerRepository {
#override
Future<List<Item>> getItem() async {
var response = await http.get("https://muslimsalat.com/riyadh.json?key=");
if (response.statusCode == 200) {
var data = json.decode(response.body);
List<Item> item = Welcome.fromJson(data).items;
return item;
} else {
throw Exception();
}
}
}
So these dart code fetch the data from api and load in HomePage when i open the application.Now the second page which is settings page, below is the code
SettingsPage.dart
class SettingsPage extends StatefulWidget {
#override
_SettingsPageState createState() => _SettingsPageState();
}
class _SettingsPageState extends State<SettingsPage> {
int selectedRadio;
#override
void initState() {
super.initState();
selectedRadio=0;
}
setSelectedRadio(int val){
setState(() {
selectedRadio=val;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
child: ListView(
children: <Widget>[
BlocBuilder<MethodBloc,MethodState>(
builder: (context,state){
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
padding: EdgeInsets.all(15.0),
child: Text(
"Prayer Methods",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
Column(
children: <Widget>[
RadioListTile(
value: 1,
groupValue: selectedRadio,
activeColor: Colors.black,
title: Text(
"Egyptian General Authority of Survey",
),
onChanged: (val) {
print(val);
setSelectedRadio(val);
}),
RadioListTile(
value: 2,
groupValue: selectedRadio,
activeColor: Colors.black,
title: Text(
"University Of Islamic Sciences, Karachi (Shafi)",
),
onChanged: (val) {
print(val);
setSelectedRadio(val);
}),
FloatingActionButton(
onPressed: (){
Navigator.pop(context);
BlocProvider.of<MethodBloc>(context).add(MethodChangedEvent(method: selectedRadio)); //I have try this code in onpressed but unfortunately not succeed
print(selectedRadio);
},
child: Text('Save')
)
],
),
],
);
},
)
],
),
),
);
}
}
MethodBloc.dart
class MethodBloc extends Bloc<MethodEvent, MethodState> {
MethodRepository methodRepository;
MethodBloc({#required this.methodRepository});
#override
MethodState get initialState => InitialMethodState();
#override
Stream<MethodState> mapEventToState(
MethodEvent event,
) async* {
if(event is MethodChangedEvent){
yield MethodLoadingState();
try {
List<Item> item = await methodRepository.getMethod(event.method);
yield MethodLoadedState(item: item);
} catch (e) {
yield MethodErrorState(message: e.toString());
}
}
}
}
MethodEvent.dart
abstract class MethodEvent extends Equatable {
const MethodEvent();
}
class MethodChangedEvent extends MethodEvent {
final int method;
MethodChangedEvent({this.method}) : assert(method != null);
#override
List<Object> get props => null;
}
MethodState.dart
abstract class MethodState extends Equatable {
const MethodState();
}
class InitialMethodState extends MethodState {
#override
List<Object> get props => [];
}
class MethodLoadingState extends MethodState {
#override
List<Object> get props => [];
}
class MethodLoadedState extends MethodState {
List<Item> item;
MethodLoadedState({#required this.item});
#override
List<Object> get props => null;
}
class MethodErrorState extends MethodState {
String message;
MethodErrorState({#required this.message});
#override
List<Object> get props => [message];
}
MethodRepository.dart
abstract class MethodRepository{
Future<List<Item>> getMethod(int method);
}
class MethodRepositoryImpl implements MethodRepository {
#override
Future<List<Item>> getMethod(int method) async {
var response = await http.get("https://muslimsalat.com/riyadh/$method.json?key=");
if (response.statusCode == 200) {
var data = json.decode(response.body);
List<Item> item = Welcome.fromJson(data).items;
return item;
} else {
throw Exception();
}
}
}
PrayerModel.dart
class Welcome {
String title;
String query;
String welcomeFor;
int method;
String prayerMethodName;
String daylight;
String timezone;
String mapImage;
String sealevel;
TodayWeather todayWeather;
String link;
String qiblaDirection;
String latitude;
String longitude;
String address;
String city;
String state;
String postalCode;
String country;
String countryCode;
List<Item> items;
int statusValid;
int statusCode;
String statusDescription;
Welcome({
this.title,
this.query,
this.welcomeFor,
this.method,
this.prayerMethodName,
this.daylight,
this.timezone,
this.mapImage,
this.sealevel,
this.todayWeather,
this.link,
this.qiblaDirection,
this.latitude,
this.longitude,
this.address,
this.city,
this.state,
this.postalCode,
this.country,
this.countryCode,
this.items,
this.statusValid,
this.statusCode,
this.statusDescription,
});
factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
title: json["title"],
query: json["query"],
welcomeFor: json["for"],
method: json["method"],
prayerMethodName: json["prayer_method_name"],
daylight: json["daylight"],
timezone: json["timezone"],
mapImage: json["map_image"],
sealevel: json["sealevel"],
todayWeather: TodayWeather.fromJson(json["today_weather"]),
link: json["link"],
qiblaDirection: json["qibla_direction"],
latitude: json["latitude"],
longitude: json["longitude"],
address: json["address"],
city: json["city"],
state: json["state"],
postalCode: json["postal_code"],
country: json["country"],
countryCode: json["country_code"],
items: List<Item>.from(json["items"].map((x) => Item.fromJson(x))),
statusValid: json["status_valid"],
statusCode: json["status_code"],
statusDescription: json["status_description"],
);
Map<String, dynamic> toJson() => {
"title": title,
"query": query,
"for": welcomeFor,
"method": method,
"prayer_method_name": prayerMethodName,
"daylight": daylight,
"timezone": timezone,
"map_image": mapImage,
"sealevel": sealevel,
"today_weather": todayWeather.toJson(),
"link": link,
"qibla_direction": qiblaDirection,
"latitude": latitude,
"longitude": longitude,
"address": address,
"city": city,
"state": state,
"postal_code": postalCode,
"country": country,
"country_code": countryCode,
"items": List<dynamic>.from(items.map((x) => x.toJson())),
"status_valid": statusValid,
"status_code": statusCode,
"status_description": statusDescription,
};
}
class Item {
String dateFor;
String fajr;
String shurooq;
String dhuhr;
String asr;
String maghrib;
String isha;
Item({
this.dateFor,
this.fajr,
this.shurooq,
this.dhuhr,
this.asr,
this.maghrib,
this.isha,
});
factory Item.fromJson(Map<String, dynamic> json) => Item(
dateFor: json["date_for"],
fajr: json["fajr"],
shurooq: json["shurooq"],
dhuhr: json["dhuhr"],
asr: json["asr"],
maghrib: json["maghrib"],
isha: json["isha"],
);
Map<String, dynamic> toJson() => {
"date_for": dateFor,
"fajr": fajr,
"shurooq": shurooq,
"dhuhr": dhuhr,
"asr": asr,
"maghrib": maghrib,
"isha": isha,
};
}
class TodayWeather {
int pressure;
String temperature;
TodayWeather({
this.pressure,
this.temperature,
});
factory TodayWeather.fromJson(Map<String, dynamic> json) => TodayWeather(
pressure: json["pressure"],
temperature: json["temperature"],
);
Map<String, dynamic> toJson() => {
"pressure": pressure,
"temperature": temperature,
};
}
Once you've defined the Model for the Stream in bloc, you can easily access the object using BlocBuilder. As demonstrated on the code you've shared, you're able to build a List with buildArticleList() from the Stream. To access a specific data, you can follow a similar approach for that object.