How to use CoinMarketCap API in flutter - api

I'm following a tutorial for an app that displays cryptocurrency prices and I have trouble with the new API. The code below is just from the tutorial and the tutor is using the old coinmarketcap API. Coinmarketcap has migrated to a new one and you need to sign up to get a free API key. Documentation for new API: https://coinmarketcap.com/api/documentation/v1.
I think I need to change _apiURL to https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?start=1&limit=5000&convert=USD and somehow use the APIKey. Does anyone have a solution? Still kinda new to flutter and API's so i'm sorry if the question is hard to answer.
Future<void> getCryptoPrices() async {
//async to use await, which suspends the current function, while it does other stuff and resumes when data ready
print('getting crypto prices'); //print
String _apiURL =
"https://api.coinmarketcap.com/v1/ticker/"; //url to get data
setState(() {
this._loading = true; //before calling the api, set the loading to true
});
http.Response response = await http.get(_apiURL); //waits for response
setState(() {
this._cryptoList =
jsonDecode(response.body); //sets the state of our widget
this._loading = false; //set the loading to false after we get a response
print(_cryptoList); //prints the list
});
return; }

You can copy paste run full code below and replace your-key before run
You can put API key in headers and parse json response with payloadFromJson and display with FutureBuilder
You can see Payload class definition in full code
Future<Payload> getCryptoPrices() async {
var response = await http.get(
"https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?start=1&limit=5000&convert=USD",
headers: {
'X-CMC_PRO_API_KEY': 'your-key',
"Accept": "application/json",
});
if (response.statusCode == 200) {
return payloadFromJson(response.body);
}
}
working demo
full code
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
Payload payloadFromJson(String str) => Payload.fromJson(json.decode(str));
String payloadToJson(Payload data) => json.encode(data.toJson());
class Payload {
Payload({
this.status,
this.data,
});
Status status;
List<Datum> data;
factory Payload.fromJson(Map<String, dynamic> json) => Payload(
status: Status.fromJson(json["status"]),
data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"status": status.toJson(),
"data": List<dynamic>.from(data.map((x) => x.toJson())),
};
}
class Datum {
Datum({
this.id,
this.name,
this.symbol,
this.slug,
this.numMarketPairs,
this.dateAdded,
this.tags,
this.maxSupply,
this.circulatingSupply,
this.totalSupply,
this.platform,
this.cmcRank,
this.lastUpdated,
this.quote,
});
int id;
String name;
String symbol;
String slug;
int numMarketPairs;
DateTime dateAdded;
List<Tag> tags;
double maxSupply;
double circulatingSupply;
double totalSupply;
Platform platform;
int cmcRank;
DateTime lastUpdated;
Quote quote;
factory Datum.fromJson(Map<String, dynamic> json) => Datum(
id: json["id"],
name: json["name"],
symbol: json["symbol"],
slug: json["slug"],
numMarketPairs: json["num_market_pairs"],
dateAdded: DateTime.parse(json["date_added"]),
tags: List<Tag>.from(json["tags"].map((x) => tagValues.map[x])),
maxSupply:
json["max_supply"] == null ? null : json["max_supply"].toDouble(),
circulatingSupply: json["circulating_supply"] == null
? null
: json["circulating_supply"].toDouble(),
totalSupply: json["total_supply"] == null
? null
: json["total_supply"].toDouble(),
platform: json["platform"] == null
? null
: Platform.fromJson(json["platform"]),
cmcRank: json["cmc_rank"],
lastUpdated: DateTime.parse(json["last_updated"]),
quote: Quote.fromJson(json["quote"]),
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"symbol": symbol,
"slug": slug,
"num_market_pairs": numMarketPairs,
"date_added": dateAdded.toIso8601String(),
"tags": List<dynamic>.from(tags.map((x) => tagValues.reverse[x])),
"max_supply": maxSupply == null ? null : maxSupply,
"circulating_supply":
circulatingSupply == null ? null : circulatingSupply,
"total_supply": totalSupply == null ? null : totalSupply,
"platform": platform == null ? null : platform.toJson(),
"cmc_rank": cmcRank,
"last_updated": lastUpdated.toIso8601String(),
"quote": quote.toJson(),
};
}
class Platform {
Platform({
this.id,
this.name,
this.symbol,
this.slug,
this.tokenAddress,
});
int id;
Name name;
Symbol symbol;
Slug slug;
String tokenAddress;
factory Platform.fromJson(Map<String, dynamic> json) => Platform(
id: json["id"],
name: nameValues.map[json["name"]],
symbol: symbolValues.map[json["symbol"]],
slug: slugValues.map[json["slug"]],
tokenAddress: json["token_address"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": nameValues.reverse[name],
"symbol": symbolValues.reverse[symbol],
"slug": slugValues.reverse[slug],
"token_address": tokenAddress,
};
}
enum Name {
ETHEREUM,
TRON,
OMNI,
RSK_SMART_BITCOIN,
BINANCE_COIN,
STELLAR,
NEO,
V_SYSTEMS,
ARDOR,
QTUM,
XRP,
WAVES,
ONTOLOGY,
EOS,
NEBULAS,
NEM,
BIT_SHARES,
BITCOIN_CASH,
INT_CHAIN,
COSMOS,
UBIQ,
VE_CHAIN,
NU_BITS,
PIVX,
COUNTERPARTY,
KOMODO,
ICON,
GX_CHAIN,
VITE,
WANCHAIN,
IOST,
TRUE_CHAIN,
ETHEREUM_CLASSIC
}
final nameValues = EnumValues({
"Ardor": Name.ARDOR,
"Binance Coin": Name.BINANCE_COIN,
"Bitcoin Cash": Name.BITCOIN_CASH,
"BitShares": Name.BIT_SHARES,
"Cosmos": Name.COSMOS,
"Counterparty": Name.COUNTERPARTY,
"EOS": Name.EOS,
"Ethereum": Name.ETHEREUM,
"Ethereum Classic": Name.ETHEREUM_CLASSIC,
"GXChain": Name.GX_CHAIN,
"ICON": Name.ICON,
"INT Chain": Name.INT_CHAIN,
"IOST": Name.IOST,
"Komodo": Name.KOMODO,
"Nebulas": Name.NEBULAS,
"NEM": Name.NEM,
"Neo": Name.NEO,
"NuBits": Name.NU_BITS,
"Omni": Name.OMNI,
"Ontology": Name.ONTOLOGY,
"PIVX": Name.PIVX,
"Qtum": Name.QTUM,
"RSK Smart Bitcoin": Name.RSK_SMART_BITCOIN,
"Stellar": Name.STELLAR,
"TRON": Name.TRON,
"TrueChain": Name.TRUE_CHAIN,
"Ubiq": Name.UBIQ,
"VeChain": Name.VE_CHAIN,
"VITE": Name.VITE,
"v.systems": Name.V_SYSTEMS,
"Wanchain": Name.WANCHAIN,
"Waves": Name.WAVES,
"XRP": Name.XRP
});
enum Slug {
ETHEREUM,
TRON,
OMNI,
RSK_SMART_BITCOIN,
BINANCE_COIN,
STELLAR,
NEO,
V_SYSTEMS,
ARDOR,
QTUM,
XRP,
WAVES,
ONTOLOGY,
EOS,
NEBULAS_TOKEN,
NEM,
BITSHARES,
BITCOIN_CASH,
INT_CHAIN,
COSMOS,
UBIQ,
VECHAIN,
NUBITS,
PIVX,
COUNTERPARTY,
KOMODO,
ICON,
GXCHAIN,
VITE,
WANCHAIN,
IOSTOKEN,
TRUECHAIN,
ETHEREUM_CLASSIC
}
final slugValues = EnumValues({
"ardor": Slug.ARDOR,
"binance-coin": Slug.BINANCE_COIN,
"bitcoin-cash": Slug.BITCOIN_CASH,
"bitshares": Slug.BITSHARES,
"cosmos": Slug.COSMOS,
"counterparty": Slug.COUNTERPARTY,
"eos": Slug.EOS,
"ethereum": Slug.ETHEREUM,
"ethereum-classic": Slug.ETHEREUM_CLASSIC,
"gxchain": Slug.GXCHAIN,
"icon": Slug.ICON,
"int-chain": Slug.INT_CHAIN,
"iostoken": Slug.IOSTOKEN,
"komodo": Slug.KOMODO,
"nebulas-token": Slug.NEBULAS_TOKEN,
"nem": Slug.NEM,
"neo": Slug.NEO,
"nubits": Slug.NUBITS,
"omni": Slug.OMNI,
"ontology": Slug.ONTOLOGY,
"pivx": Slug.PIVX,
"qtum": Slug.QTUM,
"rsk-smart-bitcoin": Slug.RSK_SMART_BITCOIN,
"stellar": Slug.STELLAR,
"tron": Slug.TRON,
"truechain": Slug.TRUECHAIN,
"ubiq": Slug.UBIQ,
"vechain": Slug.VECHAIN,
"vite": Slug.VITE,
"v-systems": Slug.V_SYSTEMS,
"wanchain": Slug.WANCHAIN,
"waves": Slug.WAVES,
"xrp": Slug.XRP
});
enum Symbol {
ETH,
TRX,
OMNI,
RBTC,
BNB,
XLM,
NEO,
VSYS,
ARDR,
QTUM,
XRP,
WAVES,
ONT,
EOS,
NAS,
XEM,
BTS,
BCH,
INT,
ATOM,
UBQ,
VET,
USNBT,
PIVX,
XCP,
KMD,
ICX,
GXC,
VITE,
WAN,
IOST,
TRUE,
ETC
}
final symbolValues = EnumValues({
"ARDR": Symbol.ARDR,
"ATOM": Symbol.ATOM,
"BCH": Symbol.BCH,
"BNB": Symbol.BNB,
"BTS": Symbol.BTS,
"EOS": Symbol.EOS,
"ETC": Symbol.ETC,
"ETH": Symbol.ETH,
"GXC": Symbol.GXC,
"ICX": Symbol.ICX,
"INT": Symbol.INT,
"IOST": Symbol.IOST,
"KMD": Symbol.KMD,
"NAS": Symbol.NAS,
"NEO": Symbol.NEO,
"OMNI": Symbol.OMNI,
"ONT": Symbol.ONT,
"PIVX": Symbol.PIVX,
"QTUM": Symbol.QTUM,
"RBTC": Symbol.RBTC,
"TRUE": Symbol.TRUE,
"TRX": Symbol.TRX,
"UBQ": Symbol.UBQ,
"USNBT": Symbol.USNBT,
"VET": Symbol.VET,
"VITE": Symbol.VITE,
"VSYS": Symbol.VSYS,
"WAN": Symbol.WAN,
"WAVES": Symbol.WAVES,
"XCP": Symbol.XCP,
"XEM": Symbol.XEM,
"XLM": Symbol.XLM,
"XRP": Symbol.XRP
});
class Quote {
Quote({
this.usd,
});
Usd usd;
factory Quote.fromJson(Map<String, dynamic> json) => Quote(
usd: Usd.fromJson(json["USD"]),
);
Map<String, dynamic> toJson() => {
"USD": usd.toJson(),
};
}
class Usd {
Usd({
this.price,
this.volume24H,
this.percentChange1H,
this.percentChange24H,
this.percentChange7D,
this.marketCap,
this.lastUpdated,
});
double price;
double volume24H;
double percentChange1H;
double percentChange24H;
double percentChange7D;
double marketCap;
DateTime lastUpdated;
factory Usd.fromJson(Map<String, dynamic> json) => Usd(
price: json["price"] == null ? null : json["price"].toDouble(),
volume24H:
json["volume_24h"] == null ? null : json["volume_24h"].toDouble(),
percentChange1H: json["percent_change_1h"] == null
? null
: json["percent_change_1h"].toDouble(),
percentChange24H: json["percent_change_24h"] == null
? null
: json["percent_change_24h"].toDouble(),
percentChange7D: json["percent_change_7d"] == null
? null
: json["percent_change_7d"].toDouble(),
marketCap:
json["market_cap"] == null ? null : json["market_cap"].toDouble(),
lastUpdated: DateTime.parse(json["last_updated"]),
);
Map<String, dynamic> toJson() => {
"price": price == null ? null : price,
"volume_24h": volume24H == null ? null : volume24H,
"percent_change_1h": percentChange1H == null ? null : percentChange1H,
"percent_change_24h":
percentChange24H == null ? null : percentChange24H,
"percent_change_7d": percentChange7D == null ? null : percentChange7D,
"market_cap": marketCap == null ? null : marketCap,
"last_updated": lastUpdated.toIso8601String(),
};
}
enum Tag { MINEABLE }
final tagValues = EnumValues({"mineable": Tag.MINEABLE});
class Status {
Status({
this.timestamp,
this.errorCode,
this.errorMessage,
this.elapsed,
this.creditCount,
this.notice,
});
DateTime timestamp;
int errorCode;
dynamic errorMessage;
int elapsed;
int creditCount;
dynamic notice;
factory Status.fromJson(Map<String, dynamic> json) => Status(
timestamp: DateTime.parse(json["timestamp"]),
errorCode: json["error_code"],
errorMessage: json["error_message"],
elapsed: json["elapsed"],
creditCount: json["credit_count"],
notice: json["notice"],
);
Map<String, dynamic> toJson() => {
"timestamp": timestamp.toIso8601String(),
"error_code": errorCode,
"error_message": errorMessage,
"elapsed": elapsed,
"credit_count": creditCount,
"notice": notice,
};
}
class EnumValues<T> {
Map<String, T> map;
Map<T, String> reverseMap;
EnumValues(this.map);
Map<T, String> get reverse {
if (reverseMap == null) {
reverseMap = map.map((k, v) => new MapEntry(v, k));
}
return reverseMap;
}
}
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;
Future<Payload> _future;
Future<Payload> getCryptoPrices() async {
var response = await http.get(
"https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?start=1&limit=5000&convert=USD",
headers: {
'X-CMC_PRO_API_KEY': 'your-key',
"Accept": "application/json",
});
if (response.statusCode == 200) {
return payloadFromJson(response.body);
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
_future = getCryptoPrices();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: FutureBuilder(
future: _future,
builder: (context, AsyncSnapshot<Payload> 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.builder(
itemCount: snapshot.data.data.length,
itemBuilder: (context, index) {
return Card(
elevation: 6.0,
child: Padding(
padding: const EdgeInsets.only(
top: 6.0,
bottom: 6.0,
left: 8.0,
right: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(snapshot.data.data[index].name),
Spacer(),
Text(snapshot.data.data[index].lastUpdated
.toIso8601String()),
Spacer(),
Text(
snapshot.data.data[index].quote.usd.price
.toString(),
),
],
),
));
});
}
}
}));
}
}

Related

Flutter Return API Value to FutureBuilder Null

I want to get data from API and convert it List to show it to Mobile, but FutureBuilder always said my data is null. I already print my data it has the data. But when I return it to FutureBuilder it just null.
API Example
{
"success": true,
"data": {
"current_page": 1,
"data": [
{
"absence_date": "2021-02-09",
"time_in": "07:51:34",
"time_out": "17:14:28"
},
{
"absence_date": "2021-02-08",
"time_in": "07:53:56",
"time_out": "17:09:15"
},
{
"absence_date": "2021-02-05",
"time_in": "07:53:32",
"time_out": "17:17:31"
}
],
"last_page": 4
}
}
Attendance.dart -> Model
#JsonSerializable()
class Attendance {
#JsonKey()
List<dynamic> data;
#JsonKey()
int last_page;
Attendance();
factory Attendance.fromJson(Map<String, dynamic> json) => _$AttendanceFromJson(json);
Map<String, dynamic> toJson() => _$AttendanceToJson(this);
}
ListView.dart -> _fecthJobs
Widget build(BuildContext context) {
return FutureBuilder<List<Job>>(
future: _fetchJobs(),
builder: (context, snapshot) {
print(snapshot.data);
if (snapshot.hasData) {
List<Job> data = snapshot.data;
return _jobsListView(data);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
);
}
Future<List<Job>> _fetchJobs() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var email = prefs.getString('email');
await api.attendances(email).then((items) async {
if (items.success == true) {
Attendance att = Attendance.fromJson(items.data);
print(att.data);
return att.data.map((job) => new Job.fromJson(job)).toList();
}
}).catchError((e) {
print('Exception $e');
});
}
I print att.data, it has the data API, but when it in snapshot.data it say it's null

Error HTTP Post Request Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>'

I want to make a post request but suddenly it getting this error 'List' is not a subtype of type 'Map<String, dynamic>' is there something wrong with my post request because i been trying to make a post request.... Please can anybody help me fix this error that i been stuck with.
PostData.dart
class PostData extends StatefulWidget {
final Future postData;
const PostData({Key key, this.postData}) : super(key: key);
#override
_PostDataState createState() => _PostDataState(postData);
}
class _PostDataState extends State<PostData> {
_PostDataState(this.postData);
Future createPost(String url, {Map body}) async {
return http.post(url, body: body).then((http.Response response) {
final int statusCode = response.statusCode;
if (statusCode < 200 || statusCode > 400 || json == null) {
throw new Exception("Error while fetching data");
}
return Post.fromJson(json.decode(response.body));
});
}
final Future postData;
static final cREATE_POST_URL =
'https://my-json-server.typicode.com/HakimRahim46/mockjson/postData';
final TextEditingController namalokasi = TextEditingController();
final TextEditingController kodlokasi = TextEditingController();
final TextEditingController nama = TextEditingController();
final TextEditingController bodyController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
resizeToAvoidBottomPadding: false,
appBar: AppBar(
title: Text('Create Data Example'),
backgroundColor: Colors.blueAccent[700],
),
body: Container(
child: Column(children: <Widget>[
ListTile(
title: TextField(
maxLines: null,
decoration: InputDecoration(
labelText: "Kod Lokasi:",
),
controller: kodlokasi,
),
leading: IconButton(icon: Icon(Icons.map), onPressed: () {})),
ListTile(
title: TextField(
maxLines: null,
decoration: const InputDecoration(labelText: "Nama Lokasi:"),
controller: namalokasi,
),
leading: IconButton(
icon: Icon(Icons.map_rounded),
onPressed: () {},
),
),
ListTile(
title: TextField(
maxLines: null,
decoration: InputDecoration(
labelText: "Nama Pegawai:",
),
controller: nama,
),
leading: IconButton(icon: Icon(Icons.person), onPressed: () {})),
SizedBox(
height: 32,
),
RaisedButton(
onPressed: () async {
// ignore: missing_required_param
Post newPost = new Post(
id: 0,
kodlokasi: kodlokasi.text,
namalokasi: namalokasi.text,
nama: nama.text,
);
Post p = await createPost(cREATE_POST_URL, body: newPost.toMap());
print(p.kodlokasi);
// insert();
Navigator.push(
context, MaterialPageRoute(builder: (context) => MyHeader()));
// setState(() {
// print(kodlokasi.text);
// print(namalokasi.text);
// print(nama.text);
// });
},
child: Text("Submit"),
)
])));
}
}
Postjson.dart
class Post {
Post({
#required this.kodlokasi,
#required this.namalokasi,
#required this.nama,
#required this.catatan,
#required this.status,
#required this.id,
});
final String kodlokasi;
final String namalokasi;
final String nama;
final String catatan;
final String status;
final int id;
factory Post.fromJson(Map<String, dynamic> json) => Post(
kodlokasi: json["kodlokasi"],
namalokasi: json["namalokasi"],
nama: json["nama"],
catatan: json["catatan"],
status: json["status"],
id: json["id"],
);
Map toMap() {
var map = new Map();
map['kodlokasi'] = kodlokasi;
map['namalokasi'] = namalokasi;
map['nama'] = nama;
return map;
}
}
Your result is a List, not Map.
Try this. It will return List<Post>.
Future createPost(String url, {Map body}) async {
return http.post(url, body: body).then((http.Response response) {
final int statusCode = response.statusCode;
if (statusCode < 200 || statusCode > 400 || json == null) {
throw new Exception("Error while fetching data");
}
return Post.fromJson(json.decode(response.body)[0]);
});
}

Flutter : The getter 'length' was called on null

I have this error and i don't know what's wrong
════════ Exception caught by widgets library
═══════════════════════════════════ The following NoSuchMethodError
was thrown building HomeScreen(dirty, dependencies:
[_InheritedProviderScope, MediaQuery], state:
_HomeScreenState#1d9fe): The getter 'length' was called on null. Receiver: null Tried calling: length The relevant error-causing widget
was HomeScreen lib\…\View\login.dart:387 When the exception was
thrown, this was the stack
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1 _HomeScreenState.build package:chroma/…/resident/home.dart:61
#2 StatefulElement.build package:flutter/…/widgets/framework.dart:4744
#3 ComponentElement.performRebuild package:flutter/…/widgets/framework.dart:4627
#4 StatefulElement.performRebuild
I want to fetch data by using api service and show it in ListBuilder
ListView(
scrollDirection: Axis.vertical,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: [
GridView.builder(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2),
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: appProvider.homeService.length,
itemBuilder: (context, index) {
return HomeServiceList(
service: appProvider.homeService[index],
isShowDate: true,
callback: () {
},
);
},
),
],
),
and this is the class of model
class Service {
Service({
this.id,
this.name,
this.homePhoto,
this.subServices,
});
int id;
String name;
dynamic homePhoto;
List<Service> subServices;
factory Service.fromJson(Map<String, dynamic> json) => Service(
id: json["id"],
name: json["name"],
homePhoto: json["home_photo"],
subServices: List<Service>.from(
json["sub_services"].map((x) => Service.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"home_photo": homePhoto,
"sub_services": List<dynamic>.from(subServices.map((x) => x.toJson())),
};
}
and this is the function to call it
class AppProvider with ChangeNotifier {
List<Service> _homeService;
List<Service> get homeService => _homeService;
bool _isLoading = false;
bool get isLoading => _isLoading;
set isLoading(bool value) {
_isLoading = value;
notifyListeners();
}
Future<dynamic> homeListService() async {
_isLoading = true;
notifyListeners();
print('Starting request');
http.Response response =
await http.get(Environment.home, headers: Environment.requestHeader);
print('Completed request');
print('respond countryList data : ${response.body}');
Map<String, dynamic> res = json.decode(response.body);
var results;
if (res['code'] == 200) {
_homeService = [];
res['services'].forEach((v) {
_homeService.add(new Service.fromJson(v));
});
results = true;
} else {
results =
FailedRequest(code: 400, message: res['massage'], status: false);
}
_isLoading = false;
notifyListeners();
return results;
}
}
please, can anyone help me in my case !!!
Change itemCount: appProvider.homeService.length, to :
itemCount: appProvider.homeService?.length ?? 0,

Flutter : Future Builder receive null from calsses

I am trying to make live score app ,I have a model created by quiqtype.io from json :
import 'dart:convert';
Live liveFromJson(String str) => Live.fromJson(json.decode(str));
String liveToJson(Live data) => json.encode(data.toJson());
class Live {
Live({
this.success,
this.data,
});
bool success;
Data data;
factory Live.fromJson(Map<String, dynamic> json) => Live(
success: json["success"],
data: Data.fromJson(json["data"]),
);
Map<String, dynamic> toJson() => {
"success": success,
"data": data.toJson(),
};
}
class Data {
Data({
this.fixtures,
this.nextPage,
this.prevPage,
});
List<Fixture> fixtures;
String nextPage;
bool prevPage;
factory Data.fromJson(Map<String, dynamic> json) => Data(
fixtures: List<Fixture>.from(
json["fixtures"].map((x) => Fixture.fromJson(x))),
nextPage: json["next_page"],
prevPage: json["prev_page"],
);
Map<String, dynamic> toJson() => {
"fixtures": List<dynamic>.from(fixtures.map((x) => x.toJson())),
"next_page": nextPage,
"prev_page": prevPage,
};
}
class Fixture {
Fixture({
this.id,
this.date,
this.time,
this.round,
this.homeName,
this.awayName,
this.location,
this.leagueId,
this.competitionId,
this.homeId,
this.awayId,
this.competition,
this.league,
});
String id;
DateTime date;
String time;
String round;
String homeName;
String awayName;
String location;
String leagueId;
String competitionId;
String homeId;
String awayId;
Competition competition;
League league;
factory Fixture.fromJson(Map<String, dynamic> json) => Fixture(
id: json["id"],
date: DateTime.parse(json["date"]),
time: json["time"],
round: json["round"],
homeName: json["home_name"],
awayName: json["away_name"],
location: json["location"],
leagueId: json["league_id"],
competitionId: json["competition_id"],
homeId: json["home_id"],
awayId: json["away_id"],
competition: Competition.fromJson(json["competition"]),
league: json["league"] == null ? null : League.fromJson(json["league"]),
);
Map<String, dynamic> toJson() => {
"id": id,
"date":
"${date.year.toString().padLeft(4, '0')}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}",
"time": time,
"round": round,
"home_name": homeName,
"away_name": awayName,
"location": location,
"league_id": leagueId,
"competition_id": competitionId,
"home_id": homeId,
"away_id": awayId,
"competition": competition.toJson(),
"league": league == null ? null : league.toJson(),
};
}
class Competition {
Competition({
this.id,
this.name,
});
String id;
String name;
factory Competition.fromJson(Map<String, dynamic> json) => Competition(
id: json["id"],
name: json["name"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
};
}
class League {
League({
this.id,
this.name,
this.countryId,
});
String id;
String name;
String countryId;
factory League.fromJson(Map<String, dynamic> json) => League(
id: json["id"],
name: json["name"],
countryId: json["country_id"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"country_id": countryId,
};
}
the i create API service class :
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:myexpect/models/match_fixture.dart';
class Api {
Future<Live> get_fixture() async {
var fixture_model = null;
var client = http.Client();
try {
var url =
'https://livescore-api.com/api-client/fixtures/matches.json?key=xxxxxxC&secret=yyyyy&page=1';
var response = await client.get(url);
if (response.statusCode == 200) {
var jsonString = response.body;
var jsonMap = json.decode(jsonString);
fixture_model = Live.fromJson(jsonMap);
print(jsonMap ): //--- printed the list in console successfully
}
} catch (Exception) {
return fixture_model;
}
}
}
I am now trying to view this data's in future building in this page :
import 'package:flutter/material.dart';
import '../services/live_score_api.dart';
import '../models/match_fixture.dart';
class LiveScore extends StatefulWidget {
#override
_LiveScoreState createState() => _LiveScoreState();
}
class _LiveScoreState extends State<LiveScore> {
Future<Live> _fixtures;
#override
void initState() {
_fixtures = Api().get_fixture();
super.initState();
}
#override
Widget build(BuildContext context) {
return FutureBuilder<Live>(
future: _fixtures,
builder: (ctx, snapshot) {
if (snapshot.connectionState == ConnectionState.none ||
snapshot.connectionState == ConnectionState.waiting ||
snapshot.connectionState == ConnectionState.active ||
snapshot.data == null) {
return Container(
child: Text('Loading.......'),
);
} else {
return ListView.builder(
itemCount: snapshot.data.data.fixtures.length,
itemBuilder: (ctx, index) {
var data = snapshot.data.data.fixtures[index];
return Text(data.time);
});
}
},
);
}
}
when i load this page ,the list of data printed successfully at console but the future builder receive null ,therefore just the text 'Loading ...' is viewed ,and no error no exception found
You want to implement your future builder like this:
return FutureBuilder<Live>(
future: _fixtures,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
case ConnectionState.active:
// Loading widget
return CircularProgressIndicator();
case ConnectionState.done:
if (snapshot.hasError) {
// return error widget
}
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.data.fixtures.length,
itemBuilder: (ctx, index) {
var data = snapshot.data.data.fixtures[index];
return Text(data.time);
});
}
}
},
);
On top of that, you catch the exception, but you don't throw an exception. So it will not throw an error. Which is kinda what you want to know in a future builder. I recommend throwing an exception.
I found my error ,is here :
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:myexpect/models/match_fixture.dart';
class Api {
Future<Live> get_fixture() async {
var fixture_model = null;
var client = http.Client();
try {
var url =
'https://livescore-api.com/api-client/fixtures/matches.json?key=xxxxxxC&secret=yyyyy&page=1';
var response = await client.get(url);
if (response.statusCode == 200) {
var jsonString = response.body;
var jsonMap = json.decode(jsonString);
fixture_model = Live.fromJson(jsonMap);
print(jsonMap ): //--- printed the list in console successfully
}
} catch (Exception) {
return fixture_model;
}
}
}
I forgot to return the list outside catch exception ,after i added return it is fixed :
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:myexpect/models/match_fixture.dart';
class Api {
Future<Live> get_fixture() async {
var fixture_model = null;
var client = http.Client();
try {
var url =
'https://livescore-api.com/api-client/fixtures/matches.json?key=xxxxxxC&secret=yyyyy&page=1';
var response = await client.get(url);
if (response.statusCode == 200) {
var jsonString = response.body;
var jsonMap = json.decode(jsonString);
fixture_model = Live.fromJson(jsonMap);
print(jsonMap ): //--- printed the list in console successfully
}
} catch (Exception) {
return fixture_model;
}
return fixture_model; //------------I added this line that i forgot :)
}
}

How to make a basic http auth ( Login and Register ) and store the token

how are you ?
i have laravel backend with passport auth and now i want to link it with my mobile app in flutter
i want to make the auth but i'm new in flutter and i don't know how to start to do this
first i make my models
this is my first model login.dart
class Login {
final String login;
final String password;
Login (this.login,this.password);
}
my second model is register.dart
class Register {
final String email;
final String name;
final String mobile;
final String password;
Register(
this.email,
this.name,
this.mobile,
this.password,
);
}
and this is User model
class User {
final int id ;
final int active ;
final int confirmed ;
final String mobile ;
final String name ;
final String email ;
final String confirmation_code ;
User(this.id,this.active,this.confirmed,this.mobile,this.name,this.email,this.confirmation_code);
}
this is my Auth Response Model
import './User.dart';
class AuthResponse {
final String token;
final User user;
AuthResponse(
this.user, this.token
);
}
but now i don't know how to make the auth and link it with these models so can any one help please
thanks
New codes
my login page code
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/services.dart';
import '../../common/apifunctions/requestLoginAPI.dart';
import 'package:gradient_widgets/gradient_widgets.dart';
class UserLoginPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _UserLoginPage();
}
}
class _UserLoginPage extends State<UserLoginPage> {
final TextEditingController _mobileController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
#override
void initState() {
super.initState();
_saveCurrentRoute('/UserLogin');
}
_saveCurrentRoute(String lastRoute) async {
SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.setString('LastScreenRoute', lastRoute);
}
void _gloginButton() {
Navigator.pushReplacementNamed(context, '/Home');
}
void _registerButton() {
Navigator.pushNamed(context, '/UserRegister');
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
if (Navigator.canPop(context)) {
Navigator.of(context).pushNamedAndRemoveUntil(
'/Home', (Route<dynamic> route) => false);
} else {
Navigator.of(context).pushReplacementNamed('/Home');
}
},
child: Scaffold(
body: Column(
children: <Widget>[
Image.asset('assets/img/LRUI.png'),
Form(
child: Container(
//padding: EdgeInsets.only(top: 100.0),
margin: EdgeInsets.all(35.0),
child: Center(
child: Center(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
SizedBox(
height: 99.0,
),
TextFormField(
controller: _mobileController,
decoration: InputDecoration(
labelText: 'رقم الجوال',
hintText: "رقم الجوال يجب أن يكون عشر ارقام",
),
style: TextStyle(
fontSize: 18.0,
color: Colors.grey,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 11.0),
TextFormField(
controller: _passwordController,
decoration: InputDecoration(
labelText: 'الرقم السري',
),
obscureText: true,
style: TextStyle(
fontSize: 18.0,
color: Colors.grey,
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 40.0,
),
GradientButton(
gradient: const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomCenter,
colors: const <Color>[
Color(0xff4caf4e),
Color(0xff71c071),
],
),
callback: () {
SystemChannels.textInput
.invokeMethod('TextInput.hide');
requestLoginAPI(context, _mobileController.text,
_passwordController.text);
},
textStyle: TextStyle(
color: Colors.white, fontSize: 16.0),
shapeRadius: BorderRadius.circular(10.0),
child: Text(
"دخول",
),
increaseHeightBy: 20.0,
increaseWidthBy: 140.0,
),
SizedBox(
height: 35.0,
),
FlatButton(
child: Text('دخول كضيف'),
onPressed: _gloginButton,
),
FlatButton(
child: Text('تسجيل حساب جديد'),
onPressed: _registerButton,
),
],
),
),
),
),
),
),
],
),
));
}
}
and this is my my Api function code for request login
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../functions/ saveCurrentLogin.dart';
import '../functions/showDialog.dart';
import 'dart:convert';
import '../../Models/Login.dart';
import '../../Models/User.dart';
import '../../Models/AuthResponse.dart';
Future<Login> requestLoginAPI(BuildContext context, String login, String password) async {
final url = "http://188.166.172.146/Blooming/public/api/login";
Map<String, String> body = {
'login': login,
'password': password,
};
final response = await http.post(
url,
body: body,
);
if (response.statusCode == 200) {
final responseJson = json.decode(response.body);
var token = new AuthResponse.fromJson(responseJson);
saveCurrentLogin(responseJson);
Navigator.of(context).pushReplacementNamed('/About');
return Login.fromJson(responseJson);
} else {
final responseJson = json.decode(response.body);
saveCurrentLogin(responseJson);
showDialogSingleButton(context, "خطأ", "تأكد من معلومات الدخول", "موافق");
return null;
}
}
this is my save current login function code
import 'package:shared_preferences/shared_preferences.dart';
import '../../Models/AuthResponse.dart';
import '../../Models/User.dart';
saveCurrentLogin(Map responseJson) async {
SharedPreferences preferences = await SharedPreferences.getInstance();
var token = (responseJson != null && !responseJson.isEmpty) ? AuthResponse.fromJson(responseJson).token : "";
var id = (responseJson != null && !responseJson.isEmpty) ? User.fromJson(responseJson).id : 0;
var name = (responseJson != null && !responseJson.isEmpty) ? User.fromJson(responseJson).name : "";
var email = (responseJson != null && !responseJson.isEmpty) ? User.fromJson(responseJson).email : "";
var mobile = (responseJson != null && !responseJson.isEmpty) ? User.fromJson(responseJson).mobile : "";
var active = (responseJson != null && !responseJson.isEmpty) ? User.fromJson(responseJson).active : 0;
var confirmation_code = (responseJson != null && !responseJson.isEmpty) ? User.fromJson(responseJson).confirmation_code : "";
var confirmed = (responseJson != null && !responseJson.isEmpty) ? User.fromJson(responseJson).confirmed : 0;
await preferences.setString('token', (token != null && token.length > 0) ? token : "");
await preferences.setInt('id', (id != null && id > 0) ? id : 0);
await preferences.setString('name', (name != null && name.length > 0) ? name : "");
await preferences.setString('email', (email != null && email.length > 0) ? email : "");
await preferences.setString('mobile', (mobile != null && mobile.length > 0) ? mobile : "");
await preferences.setInt('active', (active != null && active > 0) ? active : 0);
await preferences.setString('confirmation_code', (confirmation_code != null && confirmation_code.length > 0) ? confirmation_code : "");
await preferences.setInt('confirmed', (confirmed != null && confirmed > 0) ? confirmed : 0);
}
this is get token function code
import 'package:shared_preferences/shared_preferences.dart';
getToken() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
String getToken = await preferences.getString("token");
return getToken;
}
this is the new login model
class Login {
final String login;
final String password;
Login(this.login, this.password);
Login.fromJson(Map<String, dynamic> json)
: login = json['login'],
password = json['password'];
}
this is auth response model
import './User.dart';
class AuthResponse {
final String token;
User user;
AuthResponse({
this.token,
this.user,
});
factory AuthResponse.fromJson(Map<String, dynamic> parsedJson){
return AuthResponse(
token: parsedJson['token'],
user: User.fromJson(parsedJson['user'])
);
}
Map<String, dynamic> toJson() => {
'token': token,
'user':user,
};
}
this is my User model
class User {
final int id;
final String name;
final String email;
final String mobile;
final int active;
final String confirmation_code;
final int confirmed;
User({
this.id,
this.name,
this.email,
this.mobile,
this.active,
this.confirmation_code,
this.confirmed,
});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'],
name: json['name'],
email: json['email'],
mobile: json['mobile'],
active: json['active'],
confirmation_code: json['confirmation_code'],
confirmed: json['confirmed'],
);
}
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'email':email,
'mobile':mobile,
'active':active,
'confirmation_code':confirmation_code,
'confirmed':confirmed,
};
}
the best way to do this by using shared preferences
1 - you need to install dependence (see the link)
2 - make your "http" request with your server to get the "auth key"
3 - create tow "shared preferences" keys :
and give the first one the name of "auth_key" to store the authentication key
and save the other one as "bool" data type, give it the name "is_login"
now in the main function of the dart, check the parameter "is_login", if its true , countenu to (home page , account ... etc), otherwise take it to the login widget
dart code to set the two keys
Future<void> setUserLogin(String auth_token) async{
SharedPreferences pref = await SharedPreferences.getInstance();
pref.setString("auth_token", auth_token);
pref.setBool("is_login", true);
}
check if login:
Future<bool> isUserLogin() async{
SharedPreferences pref = await SharedPreferences.getInstance();
return pref.getBool("is_login");
}
get the auth key:
Future<bool> isUserLogin() async{
SharedPreferences pref = await SharedPreferences.getInstance();
return pref.getString("auth_token");
}
logout method
Future<void> logout() async{
SharedPreferences pref = await SharedPreferences.getInstance();
pref.remove("auth_key");
pref.remove("is_login");
}
I just give you an example of how to do it, you need to read more about "SharedPreferences" at the link below to know more about
there is another techniques like save data to sql, but its more complicated, and I guess its less secure (cuz there is many root apps working as sqlite browsers)