How to fetch image from firestore on flutter? - flutter

I tried to fetch images and topic and descriptions for each "doc id ", Successfully fetch topic and description but when I tried to fetch image then shows "URL undefined" .For this code I used model class also.And in there I decleard "URL" and in the UI code I called that in an" Imagenetwrok widget".
code
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../articlesModel.dart';
class ViewArticlesScreens extends StatefulWidget {
const ViewArticlesScreens({Key? key}) : super(key: key);
#override
State<ViewArticlesScreens> createState() => _ViewArticlesScreensState();
}
class _ViewArticlesScreensState extends State<ViewArticlesScreens> {
#override
Future<List<Articles>> fetchRecords() async {
var records = await FirebaseFirestore.instance.collection('articles').get();
return mapRecords(records);
}
List<Articles> mapRecords(QuerySnapshot<Map<String, dynamic>> records) {
var _list = records.docs
.map(
(article) => Articles(
id: article.id,
topic: article['topic'],
description: article['description'],
url: article['url'],
),
)
.toList();
return _list;
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
return Scaffold(
body: Column(
children: [
SingleChildScrollView(
child: Column(
//chip words
children: <Widget>[
const SizedBox(height: 10),
SizedBox(
width: width * 0.94,
height: height * 0.30,
child: FutureBuilder<List<Articles>>(
future: fetchRecords(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
List<Articles> data = snapshot.data ?? [];
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return (ListTile(
leading: Image.network(
url,
height: 30,
fit: BoxFit.cover,
),
title: Text(data[index].topic),
subtitle: Text(data[index].description),
tileColor: Colors.red,
));
});
}
}))
],
),
),
],
),
);
}
}
model class
import 'dart:convert';
Articles articlesFromJson(String str) => Articles.fromJson(json.decode(str));
String articlesToJson(Articles data) => json.encode(data.toJson());
class Articles {
Articles({
required this.id,
required this.url,
required this.topic,
required this.description,
});
String id;
String topic;
String description;
String url;
factory Articles.fromJson(Map<String, dynamic> json) => Articles(
id: json["id"] ?? "",
topic: json["topic"] ?? "",
description: json["description"] ?? "",
url: json["url"] ?? "",
);
Map<String, dynamic> toJson() => {
"id": id,
"topic": topic,
"description": description,
"url": url,
};
}

you just set url instead of data[index].url
here try this :
itemBuilder: (context, index) {
return (ListTile(
leading: Image.network(
data[index].url,
height: 30,
fit: BoxFit.cover,
),
title: Text(data[index].topic),
subtitle: Text(data[index].description),
tileColor: Colors.red,
));
});
}

Related

How view single data from listView in flutter?

I fetched data from the database as a ListView.That's displayed perfectly.
output.
When clicking the view button then should display only that article's details.
Andalso for the fetch data I used model class.
All articles code
model
import 'dart:convert';
Articles articlesFromJson(String str) => Articles.fromJson(json.decode(str));
String articlesToJson(Articles data) => json.encode(data.toJson());
class Articles {
Articles({
required this.id,
required this.url,
required this.topic,
required this.description,
});
String id;
String topic;
String description;
String url;
factory Articles.fromJson(Map<String, dynamic> json) => Articles(
id: json["id"] ?? "",
topic: json["topic"] ?? "",
description: json["description"] ?? "",
url: json["url"] ?? "",
);
Map<String, dynamic> toJson() => {
"id": id,
"topic": topic,
"description": description,
"url": url,
};
}
View all articles
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:neerogi/screens/Articles/Admin/viewOne_articles.dart';
import '../articlesModel.dart';
class ViewArticlesScreens extends StatefulWidget {
const ViewArticlesScreens({Key? key}) : super(key: key);
#override
State<ViewArticlesScreens> createState() => _ViewArticlesScreensState();
}
class _ViewArticlesScreensState extends State<ViewArticlesScreens> {
#override
Future<List<Articles>> fetchRecords() async {
var records = await FirebaseFirestore.instance.collection('articles').get();
return mapRecords(records);
}
List<Articles> mapRecords(QuerySnapshot<Map<String, dynamic>> records) {
var _list = records.docs
.map(
(article) => Articles(
id: article.id,
topic: article['topic'],
description: article['description'],
url: article['url'],
),
)
.toList();
return _list;
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
return Scaffold(
body: Column(
children: [
SingleChildScrollView(
child: Column(
//chip words
children: <Widget>[
const SizedBox(height: 10),
SizedBox(
width: width * 0.94,
height: height * 0.90,
child: FutureBuilder<List<Articles>>(
future: fetchRecords(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
List<Articles> data = snapshot.data ?? [];
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return (SizedBox(
height: 100,
child: Column(
children: <Widget>[
ListTile(
leading: Image.network(
data[index].url,
height: 30,
fit: BoxFit.cover,
),
title: Text(data[index].topic),
subtitle:
Text(data[index].description),
trailing: ElevatedButton(
child: Text('View'),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
ViewOneArticleScreen(
id: article.id,
)));
},
))
],
),
));
});
}
}))
],
),
),
],
),
);
}
}
View one article code
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../articlesModel.dart';
class ViewOneArticleScreen extends StatefulWidget {
const ViewOneArticleScreen({Key? key}) : super(key: key);
#override
State<ViewOneArticleScreen> createState() => _ViewOneArticleScreenState();
}
class _ViewOneArticleScreenState extends State<ViewOneArticleScreen> {
Future<List<Articles>> fetchRecords() async {
var records = await FirebaseFirestore.instance.collection('articles').get();
return mapRecords(records);
}
List<Articles> mapRecords(QuerySnapshot<Map<String, dynamic>> records) {
var _list = records.docs
.map(
(article) => Articles(
id: article.id,
topic: article['topic'],
description: article['description'],
url: article['url'],
),
)
.toList();
return _list;
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
return Scaffold(
body: Column(
children: [
Image.network(
data[index].url,
height: 30,
fit: BoxFit.cover,
),
Text($topic),
Text($description),
],
),
);
}
}
How to view one article data from the list view?
Ex:- User when cleck article 1 view button then should redirect to the View one article page and in there should display article 1 image , topic , description.

flutter futurebuilder asyncsnapshot to fetch data that is not list

Below is the list of data that i am fetching
[
{
"name": "kamchatka11111",
"email": "kamchatka#mail.com",
"index": 1,
"picture": "https://static.themoscowtimes.com/image/1360/73/TASS40183186.jpg",
"imageFetchType": "networkImage"
},
{
"name": "Valjakutse",
"email": "valjakutse#mail.com",
"index": 2,
"picture": "https://images.unsplash.com/photo-1561406636-b80293969660?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8M3x8YmxhY2slMjBsYWR5fGVufDB8fDB8fA%3D%3D&w=1000&q=80",
"imageFetchType": "imageNetwork"
},
{
"name": "einstein",
"email": "einstein#mail.com",
"index": 12,
"picture": "https://static.dw.com/image/45897958_303.jpg",
"imageFetchType": "fadeInImage"
}
]
Below is how i am populating this list in my flutter class
import 'package:flutter/material.dart';
import 'package:master_learn/classes/async_futures.dart';
import 'package:master_learn/classes/config.dart';
import 'package:master_learn/lists_grids_screens/user_details.dart';
import 'package:master_learn/widgets/marquee_widget.dart';
class FutureBuilderListUsingHashMap extends StatefulWidget {
const FutureBuilderListUsingHashMap({Key? key}) : super(key: key);
#override
_FutureBuilderListUsingHashMapState createState() =>
_FutureBuilderListUsingHashMapState();
}
class _FutureBuilderListUsingHashMapState
extends State<FutureBuilderListUsingHashMap> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
onPressed: () => Navigator.of(context).pop(),
icon: const Icon(
Icons.arrow_back,
color: Colors.white,
)),
title: const SizedBox(
child: MarqueeWidget(
direction: Axis.horizontal,
child: Text(
"Fetch"),
),
),
),
body: SizedBox(
child: FutureBuilder(
future: AsyncFutures.fetchListsOfStringDynamicHashMap(),
builder: (BuildContext context, AsyncSnapshot asyncSnapshot) {
if (asyncSnapshot.data == null) {
return const Center(child: CircularProgressIndicator());
} else {
return ListView.builder(
itemCount: asyncSnapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
contentPadding: const EdgeInsets.all(10),
leading: CircleAvatar(
backgroundImage: NetworkImage(
asyncSnapshot.data[index]["picture"] ??
""),
),
title:
Text(asyncSnapshot.data[index]["name"] ?? ''),
subtitle: Text(
"Email: ${asyncSnapshot.data[index]["email"] ?? ''}"),
);
},
);
}
}),
),
);
}
}
The problem i am having is how can i use AsyncSnapshot with FutureBuilder to populate data that is not of a list for example the data below
{
"name": "einstein",
"email": "einstein#mail.com",
"index": 12,
"picture": "https://static.dw.com/image/45897958_303.jpg",
"imageFetchType": "fadeInImage"
}
This may be for example when i am fetching the information for a single profile instead of a list of information of all the profiles
Use the FutureBuilder instead of ListView.builder to fetch a single object. Refer to this awesome explanation in the flutter docs:
https://docs.flutter.dev/cookbook/networking/fetch-data#1-add-the-http-package
To encode your json data into proper flutter object you can visit this website
https://app.quicktype.io/
Hi Emmanuel hope you are well
A recommended practice would be to map your class, converting it from JSON to a class.
Profile class:
class Profile{
final String name;
final String image;
Profile({
#required this.name,
#required this.image,
});
factory Profile.fromJson(Map<String, dynamic> json) {
return Profile(
name: json['name'] as String,
image: json['image'] as String,
);
}
}
Your data request class
class HttpService {
final String profilesURL = "https://sourceDataUrl.example";
Future<List<Profile>> getProfiles() async {
Response res = await get(profilesURL);
if (res.statusCode == 200) {
List<dynamic> body = jsonDecode(res.body);
List<Profile> profiles = body
.map(
(dynamic item) => Profile.fromJson(item),
)
.toList();
return profiles;
} else {
throw "Unable to retrieve profiles.";
}
}
}
and get the request data in a FutureBuilder
class ProfilesPage extends StatelessWidget {
final HttpService httpService = HttpService();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Profile"),
),
body: FutureBuilder(
future: httpService.getProfiles(),
builder: (BuildContext context, AsyncSnapshot<List<Profile>> snapshot) {
if (snapshot.hasData) {
List<Profile> listProfile = snapshot.data;
return ListView(
children: listProfile
.map(
(Profile profile) => ListTile(
name: Text(profile.name),
),
)
.toList(),
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
);
}
}
You can refer to this link for more information about http requests.

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)

Pass data from future to another future in the same page

I'm new to the Flutter world and mobile app development and struggling with how I should pass data throughout my app. This is my code, How can I pass data from future to another future on the same page? these are my two futures and my class and my HomePage with the futurebuilders
help, please.
This is my future that returns the Location. From her I need to pass the Location id to the next future.
Future<Location> Lastlocation() async {
final prefs = await SharedPreferences.getInstance();
final key = 'token';
final value = prefs.get(key) ?? 0;
String myUrl = "$serverUrl/location/getlastlocation?token=" + value;
http.Response response = await http.get(
myUrl,
headers: {
'Accept': 'application/json',
//'Authorization': 'token $value'
},
);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
return Location.fromJson(json.decode(response.body));
} else {
// then throw an exception.
throw Exception('Failed to load album');
}
}
**This is the second future that returns a List of weather that depends on location id from the first future *Lastlocation()
Future<List> Getweither(String ID) async {
final prefs = await SharedPreferences.getInstance();
final key = 'token';
final value = prefs.get(key) ?? 0;
String myUrl = "$serverUrl/dashbaord/Getweither/$ID?token=" + value;
http.Response response = await http.get(myUrl,
headers: {
'Accept': 'application/json',
});
print("myUrldevice :"+myUrl);
print("status :"+response.statusCode.toString());
return json.decode(response.body);
}
This is my class Location
// To parse this JSON data, do
//
// final location = locationFromJson(jsonString);
import 'dart:convert';
List<Location> locationFromJson(String str) => List<Location>.from(json.decode(str).map((x) => Location.fromJson(x)));
String locationToJson(List<Location> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Location {
Location({
this.automaticIrrigation,
this.coordinates,
this.createdDate,
this.sensorIds,
this.id,
this.siteName,
this.description,
this.v,
});
bool automaticIrrigation;
List<double> coordinates;
DateTime createdDate;
List<String> sensorIds;
String id;
String siteName;
String description;
int v;
factory Location.fromJson(Map<String, dynamic> json) => Location(
automaticIrrigation: json["AutomaticIrrigation"],
coordinates: List<double>.from(json["Coordinates"].map((x) => x.toDouble())),
createdDate: DateTime.parse(json["Created_date"]),
sensorIds: List<String>.from(json["Sensor_ids"].map((x) => x)),
id: json["_id"],
siteName: json["SiteName"],
description: json["Description"],
v: json["__v"],
);
Map<String, dynamic> toJson() => {
"AutomaticIrrigation": automaticIrrigation,
"Coordinates": List<dynamic>.from(coordinates.map((x) => x)),
"Created_date": createdDate.toIso8601String(),
"Sensor_ids": List<dynamic>.from(sensorIds.map((x) => x)),
"_id": id,
"SiteName": siteName,
"Description": description,
"__v": v,
};
}
and this is my homePage
import 'dart:convert';
import 'dart:developer';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:sidebar_animation/Services/DataHelpers.dart';
import 'package:sidebar_animation/sidebar/sidebar_layout.dart';
import '../bloc.navigation_bloc/navigation_bloc.dart';
import 'package:sidebar_animation/constants.dart';
import 'package:flutter/gestures.dart';
import 'package:sidebar_animation/bloc.navigation_bloc/navigation_bloc.dart';
class HomePage extends StatelessWidget with NavigationStates {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
DatabaseHelper2 databaseHelper2 = new DatabaseHelper2();
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
body: ListView(
FutureBuilder(
future: databaseHelper2.Getweither(location_id),
builder: (context,snapshot) {
if (snapshot.hasError)
{
print(snapshot.error);
print("there is problem !");
}
return snapshot.hasData
? ItemList(list: snapshot.data)
: Center(child: CircularProgressIndicator(
),
);
}
),
);
}
Widget _buildProgrammCard() {
return Container(
height: 90,
child:
Card(
semanticContainer: true,
clipBehavior: Clip.antiAliasWithSaveLayer,
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 4,
margin: EdgeInsets.fromLTRB(14, 0, 14, 14),
child:
FutureBuilder(
future: databaseHelper2.Lastlocation(),
builder: (context,snapshot) {
if (snapshot.hasError)
{
print(snapshot.error);
print("mochkla lenaa *");
}
return snapshot.hasData
? Text("Location :" +snapshot.data.siteName)
: Center(child: CircularProgressIndicator(
),
);
}
),
),
);
}
class ItemList extends StatelessWidget{
List list;
ItemList({this.list});
ScrollController _controller = new ScrollController();
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: list == null ? 0 : list.length,
scrollDirection: Axis.horizontal,
itemExtent: 190.0,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 0, 14),
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
item.storyUrl,
),
fit: BoxFit.cover,
colorFilter: ColorFilter.mode(
Colors.black26,
BlendMode.darken,
),
),
borderRadius: BorderRadius.circular(10.0),
color: Colors.grey,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
"temp :",
style: TextStyle(color: Colors.white),
),
),
Padding(
padding: EdgeInsets.only(left: 24),
child:
Text(
list[i]['Weither']['Temp'],
),
),
],
),
),
);
},
),
}
}
Finally, I need to get the location id from the first future that returns the Location to the second future Getweither(String ID) to get the weather of a specified location.
Just nest the two FutureBuilders, and pass the snapshot.data as a parameter of the second one.
Minimalistic example:
FutureBuilder(
future: databaseHelper2.Lastlocation(),
builder: (context, snapshot) {
if (snapshot.hasError) {
print(snapshot.error);
print("there is problem !");
}
return snapshot.hasData
? FutureBuilder(
future: databaseHelper2.Getweither(snapshot.data.id),
builder: (context, snapshot2) {...})
: Center(child: CircularProgressIndicator());
}
);

Flutter - Argument type 'List<List<SubCategoriesFolder>> Function(String)' can't be assigned to the parameter type

I'm trying to apply the function compute to get the data from responseJSON.
I used quicktype.io to generate the function for this purpose.
This is what i have done so far:
final subCategoriesFolder = await compute(subCategoriesFolderFromJson, responseJSON);
Error 1:
error: The argument type 'List<List<SubCategoriesFolder>> Function(String)' can't be assigned to the parameter type 'FutureOr<List<List<SubCategoriesFolder>>> Function(dynamic)'. (argument_type_not_assignable at lib\src\ui\pages\subcategories.dart:84)
Error 2:
error: Couldn't infer type parameter 'Q'.
Tried to infer 'dynamic' for 'Q' which doesn't work:
Parameter 'callback' declared as 'FutureOr<R> Function(Q)'
but argument is 'List<List<SubCategoriesFolder>> Function(String)'.
The type 'dynamic' was inferred from:
Parameter 'message' declared as 'Q'
but argument is 'dynamic'.
Consider passing explicit type argument(s) to the generic.
(could_not_infer at lib\src\ui\pages\subcategories.dart:84)
Source:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:flutter/foundation.dart';
// import 'dart:isolate';
// import 'package:flutter/foundation.dart';
// import 'catwidget.dart';
// To parse this JSON data, do
//
// final subCategoriesFolder = subCategoriesFolderFromJson(jsonString);
List<List<SubCategoriesFolder>> subCategoriesFolderFromJson(String str) => List<List<SubCategoriesFolder>>.from(json.decode(str).map((x) => List<SubCategoriesFolder>.from(x.map((x) => SubCategoriesFolder.fromJson(x)))));
String subCategoriesFolderToJson(List<List<SubCategoriesFolder>> data) => json.encode(List<dynamic>.from(data.map((x) => List<dynamic>.from(x.map((x) => x.toJson())))));
class SubCategoriesFolder {
SubCategoriesFolder({
this.children,
this.title,
});
List<Child> children;
String title;
factory SubCategoriesFolder.fromJson(Map<String, dynamic> json) => SubCategoriesFolder(
children: List<Child>.from(json["children"].map((x) => Child.fromJson(x))),
title: json["title"],
);
Map<String, dynamic> toJson() => {
"children": List<dynamic>.from(children.map((x) => x.toJson())),
"title": title,
};
}
class Child {
Child({
this.title,
this.uri,
this.iconuri,
this.charset,
});
String title;
String uri;
String iconuri;
String charset;
factory Child.fromJson(Map<String, dynamic> json) => Child(
title: json["title"],
uri: json["uri"],
iconuri: json["iconuri"] == null ? null : json["iconuri"],
charset: json["charset"] == null ? null : json["charset"],
);
Map<String, dynamic> toJson() => {
"title": title,
"uri": uri,
"iconuri": iconuri == null ? null : iconuri,
"charset": charset == null ? null : charset,
};
}
class Subfolder extends StatefulWidget {
#override
SubFolder createState() => SubFolder();
}
class SubFolder extends State<Subfolder> {
Future _fetchJSON() async {
var response = await http.get(
"http://10.0.2.2:5000/subcategories",
headers: {"Accept": "application/json"},
);
if (response.statusCode == 200) {
String responseBody = response.body;
//var responseJSON = json.decode(responseBody);
var responseJSON = await compute(jsonDecode, responseBody);
//final subCategoriesFolder = subCategoriesFolderFromJson(responseJSON);
final subCategoriesFolder = await compute(subCategoriesFolderFromJson, responseJSON);
print(subCategoriesFolder.runtimeType);//THis is not being set, error here
print(subCategoriesFolder);
// name = responseJSON['name'];
// avatar = responseJSON['avatar_url'];
}
return true;
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: CupertinoColors.darkBackgroundGray,
body: FutureBuilder(
future: _fetchJSON(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.data == null) {
return Center(child: Text('No data'));
} else
return Container(
child: Text(snapshot.data),
);
/*return GridView(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
children: <Widget>[
for(var item in snapshot.data ) singleCategoryTemp(item)
],
); */
} else if (snapshot.connectionState == snapshot.error) {
return Center(
child: Text('Error: Please try again later')); // error
} else {
return Center(child: CircularProgressIndicator()); // loading
}
}),
);
}
}
You can copy paste run full code below
You can use compute(subCategoriesFolderFromJson, responseBody)
I use nested ListView to show data, you check full code
code snippet
Future<List<List<SubCategoriesFolder>>> _fetchJSON() async {
...
if (response.statusCode == 200) {
String responseBody = response.body;
return compute(subCategoriesFolderFromJson, responseBody);
}
working demo
full code
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
List<List<SubCategoriesFolder>> subCategoriesFolderFromJson(String str) =>
List<List<SubCategoriesFolder>>.from(json.decode(str).map((x) =>
List<SubCategoriesFolder>.from(
x.map((x) => SubCategoriesFolder.fromJson(x)))));
String subCategoriesFolderToJson(List<List<SubCategoriesFolder>> data) =>
json.encode(List<dynamic>.from(
data.map((x) => List<dynamic>.from(x.map((x) => x.toJson())))));
class SubCategoriesFolder {
SubCategoriesFolder({
this.children,
this.title,
});
List<Child> children;
String title;
factory SubCategoriesFolder.fromJson(Map<String, dynamic> json) =>
SubCategoriesFolder(
children:
List<Child>.from(json["children"].map((x) => Child.fromJson(x))),
title: json["title"],
);
Map<String, dynamic> toJson() => {
"children": List<dynamic>.from(children.map((x) => x.toJson())),
"title": title,
};
}
class Child {
Child({
this.title,
this.uri,
this.iconuri,
this.charset,
});
String title;
String uri;
String iconuri;
String charset;
factory Child.fromJson(Map<String, dynamic> json) => Child(
title: json["title"],
uri: json["uri"],
iconuri: json["iconuri"] == null ? null : json["iconuri"],
charset: json["charset"] == null ? null : json["charset"],
);
Map<String, dynamic> toJson() => {
"title": title,
"uri": uri,
"iconuri": iconuri == null ? null : iconuri,
"charset": charset == null ? null : charset,
};
}
class Subfolder extends StatefulWidget {
#override
SubFolder createState() => SubFolder();
}
class SubFolder extends State<Subfolder> {
Future<List<List<SubCategoriesFolder>>> _fetchJSON() async {
/*var response = await http.get(
"http://10.0.2.2:5000/subcategories",
headers: {"Accept": "application/json"},
);*/
String jsonString = '''
[[
{
"title" : "1",
"children" : [{
"title":"abc1",
"uri" : "def1",
"iconuri" : "123",
"charset" : "456"
},
{
"title":"abc2",
"uri" : "def1",
"iconuri" : "123",
"charset" : "456"
}]
},
{
"title" : "2",
"children" : [{
"title":"abc2",
"uri" : "def2",
"iconuri" : "789",
"charset" : "321"
}]
}
]]
''';
http.Response response = http.Response(jsonString, 200);
if (response.statusCode == 200) {
String responseBody = response.body;
return compute(subCategoriesFolderFromJson, responseBody);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
//backgroundColor: CupertinoColors.darkBackgroundGray,
body: FutureBuilder(
future: _fetchJSON(),
builder: (BuildContext context,
AsyncSnapshot<List<List<SubCategoriesFolder>>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('none');
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.active:
return Text('');
case ConnectionState.done:
if (snapshot.hasError) {
return Text(
'${snapshot.error}',
style: TextStyle(color: Colors.red),
);
} else {
return ListView.separated(
separatorBuilder: (BuildContext context, int index) {
return SizedBox(
height: 10,
);
},
shrinkWrap: true,
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
/* Expanded(
flex: 1, child: Text(snapshot.data[index].toString())),*/
Expanded(
flex: 2,
child: Container(
height: 50,
child: ListView.separated(
separatorBuilder:
(BuildContext context,
int index) {
return SizedBox(
width: 10,
);
},
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount:
snapshot.data[index].length,
itemBuilder: (context, index1) {
return Row(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: <Widget>[
Container(
width: 120,
child: Column(
children: <Widget>[
Text(
snapshot
.data[index]
[index1]
.title,
style: TextStyle(
color:
Colors.red),
),
Expanded(
child: ListView
.separated(
separatorBuilder:
(BuildContext
context,
int
index) {
return SizedBox(
width:
2,
);
},
shrinkWrap:
true,
scrollDirection:
Axis
.horizontal,
itemCount: snapshot
.data[
index]
[
index1]
.children
.length,
itemBuilder:
(context,
index2) {
return Row(
mainAxisAlignment: MainAxisAlignment
.spaceEvenly,
children: <
Widget>[
Text(snapshot.data[index][index1].children[index2].title,
style: TextStyle(color: Colors.red)),
]);
}),
),
],
),
)
]);
}),
),
)
])
],
);
});
}
}
}));
}
}
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: Subfolder(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}