flutter: Unhandled Exception: type 'Null' is not a subtype of type 'String' - flutter

I tried to use Moralis API to call NFT via wallet address, but got following error.
Unhandled Exception: type 'Null' is not a subtype of type 'String'
These are the code lines that were pointed out as having errors.
final meta = jsonDecode(map?['metadata']);
meta_name = meta['name'] ?? '';
meta_image = meta['image'] ?? '';
meta_description = meta['description'] ?? '';
if (response.statusCode == 200) {
nfts = jsonDecode(response.body)['result'].map<Nfts>((result) {
return Nfts.fromMap(result);
}).toList();
}
The full code for the first one is below.
import 'dart:convert';
class Nfts {
late String total;
late String page;
late String page_size;
late String cursor;
late String result;
late String token_id;
late String token_address;
late String amount;
late String owner_of;
late String token_hash;
late String block_number_minted;
late String block_number;
late String contract_type;
late String name;
late String symbol;
late String token_uri;
late String metadata;
late String last_token_uri_sync;
late String last_metadata_sync;
late String minter_address;
late String meta_name;
late String meta_image;
late String meta_description;
Nfts({
required this.total,
required this.page,
required this.page_size,
required this.cursor,
required this.result,
required this.token_id,
required this.token_address,
required this.amount,
required this.owner_of,
required this.token_hash,
required this.block_number_minted,
required this.block_number,
required this.contract_type,
required this.name,
required this.symbol,
required this.token_uri,
required this.metadata,
required this.last_token_uri_sync,
required this.last_metadata_sync,
required this.minter_address,
required this.meta_name,
required this.meta_image,
required this.meta_description,
});
Nfts.fromMap(Map<String, dynamic>? map) {
total = map?['total'] ?? '';
page = map?['page'] ?? '';
page_size = map?['page_size'] ?? '';
cursor = map?['cursor'] ?? '';
result = map?['result'] ?? '';
token_id = map?['token_id'] ?? '';
token_address = map?['token_address'] ?? '';
amount = map?['amount'] ?? '';
owner_of = map?['owner_of'] ?? '';
token_hash = map?['token_hash'] ?? '';
block_number_minted = map?['block_number_minted'] ?? '';
block_number = map?['block_number'] ?? '';
contract_type = map?['contract_type'] ?? '';
name = map?['name'] ?? '';
symbol = map?['symbol'] ?? '';
token_uri = map?['token_uri'] ?? '';
metadata = map?['metadata'] ?? '';
last_token_uri_sync = map?['last_token_uri_sync'] ?? '';
last_metadata_sync = map?['last_metadata_sync'] ?? '';
minter_address = map?['minter_address'] ?? '';
final meta = jsonDecode(map?['metadata']);
meta_name = meta['name'] ?? '';
meta_image = meta['image'] ?? '';
meta_description = meta['description'] ?? '';
}
}
The full code for the second one is below.
class NftsProviders{
Uri uri = Uri.parse('https://deep-index.moralis.io/api/v2/(personal metamask wallet address)/nft?chain=polygon&format=decimal');
Future<List<Nfts>> getNfts() async {
List<Nfts> nfts = [];
final response = await http.get(uri, headers: {
'accept': 'application/json',
'X-API-Key' : 'o1g9ywaRjZvZaeaByxhZc7mFOBVVvDJEksU0jeZ8b34fNX03ISTc72fltfsAnuYG'
});
if (response.statusCode == 200) {
nfts = jsonDecode(response.body)['result'].map<Nfts>((result) {
return Nfts.fromMap(result);
}).toList();
}
else {
throw Exception('Failed to load NFT');
}
return nfts;
}
}
With this API, I tried to create a Gridview.builder.
class NftsScreen extends StatefulWidget {
#override
_NftsScreenState createState() {
return new _NftsScreenState();
}
}
class _NftsScreenState extends State<NftsScreen> {
List<Nfts> nfts = [];
bool isLoading = true;
NftsProviders nftsProvider = NftsProviders();
Future initNfts() async {
nfts = await nftsProvider.getNfts();
}
#override
void initState() {
super.initState();
initNfts().then((_) {
setState(() {
isLoading = false;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("nfts http"),
),
body: isLoading
? Center(
child: const CircularProgressIndicator(),
)
: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.5,
crossAxisSpacing: 20,
mainAxisSpacing: 20),
itemCount: nfts.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.all(8.0),
child: Column(
children: [
// Text(nfts[index].name),
// Text(nfts[index].metadata),
CupertinoButton(
onPressed: () {},
// CircleAvatar with NetworkImage(nfts[index].meta_image)
// size of 100, 100
child: CircleAvatar(
radius: 100,
backgroundImage: NetworkImage(nfts[index].meta_image,),
)
)
],
),
);
}),
);
}
}
I want to request NFT information according to the user's wallet address called from Firebase.
Thanks in advance.
This is part of the api call response.
{
"total": null,
"page": 1,
"page_size": 100,
"cursor": null,
"result": [
{
"token_address": "0x53a0018f919bde9c254bda697966c5f448ffddcb",
"token_id": "46388765668907266497641806581710410401632846941109288029645926940148068689172",
"owner_of": "0xe3281571a136c11cc66d225902d494d29aaf7cb9",
"block_number": "30362645",
"block_number_minted": "30362645",
"token_hash": "8b025de30055bd161b2774da64fc283a",
"amount": "1",
"contract_type": "ERC721",
"name": "EDNS",
"symbol": "EDNS",
"token_uri": "https://api.edns.domains/metadata/0x53a0018f919bde9c254bda697966c5f448ffddcb/46388765668907266497641806581710410401632846941109288029645926940148068689172/metadata.json",
"metadata": "{\"name\":\"goyangtwo.meta\",\"description\":\"Domain goyangtwo.meta from EDNS Domains\",\"image\":\"https://api.edns.domains/metadata/0x53a0018f919bde9C254bda697966C5f448ffDDcB/46388765668907266497641806581710410401632846941109288029645926940148068689172/image.svg\",\"attributes\":[{\"trait_type\":\"TLD\",\"value\":\"meta\"}]}",
"last_token_uri_sync": "2022-12-06T14:08:39.924Z",
"last_metadata_sync": "2022-12-06T14:08:44.789Z",
"minter_address": "0x805ec22fca66eca02e244689b47fc2f180a94f01"
}
],
"status": "SYNCED"
}

can you share the response of the api call, most probably there will be a typo in the JSON decoding
meta_name = meta['name'] ?? '';
meta_image = meta['image'] ?? '';
meta_description = meta['description'] ?? '';
try quicktype.io to generate response models

What's the source of Nfts? Do you not have accidently defined a field like cursor or total as String instead of String? Otherwise, please provide the code for Nfts as it might have fields of type String without defaults that are not present in the json, causing the Nfts.fromMap(result); to fail.
As a general tip, it is wise to NOT assume that this will always succeed. In case it fails, then i.e. return null instead of crashing your app.
Edit added solution:
In the function
Nfts.fromMap(Map<String, dynamic>? map) {}
the variable map will be the full map (with total, page, result, etc. entries) which does not contain a metadata tag, so...
final meta = jsonDecode(map?['metadata']);
will be the same as
final meta = jsonDecode(null);
which is the reason for the error message. A string is expected!
However, you already jsonDecode (d) the response, so why do it again, because you already have a map of the response :)
You just need to pick the right tags from the map.
final result = map?['result'];
final metadata = result?['metadata'];
meta_name = metadata?['name'] ?? '';
meta_image = metadata?['image'] ?? '';
meta_description = metadata?['description'] ?? '';
final result = map?['result'];
final metadata = result?['metadata'];
meta_name = metadata?['name'] as String? ?? '';
meta_image = metadata?['image'] as String? ?? '';
meta_description = metadata?['description'] as String? ?? '';

Related

How can I use List<String> in a for loop to both generate column name AND value of that column?

I have a Flutter app that gets data from an SQLite database. That database has a table with a huge number of columns, so I've written a function that puts those column names into a list.
Therefore, columnsList contains list of the columns in my database table.
How can I use columnsList to BOTH display the name of the column AND the VALUE of that column in a for loop?
Pseudocode
List<String> columnsList = [];
columnsList = ['RecordId', 'FirstName', 'MiddleName', 'LastName', 'Suffix', 'StreetNumber', 'StreetName'];
fetchRecord(1); // Inside initState() - returns values shown in example output
for (var i in columnsList) ...[
Text("$i: <<<VALUE OF i>>>"), // Here's where I need help
],
fetchRecord
Fetch Record looks something like this with a huge list of variables that I'd like to replace with the list.
//--- Fetch Record ---
bool isLoading = true;
List<Map<String, dynamic>> myRecord = [];
void fetchRecord(int recordId) async {
final data = await SQLiteMethods.getRecord(recordId);
setState(() {
myRecord = data;
firstName = myRecord[0]["FirstName"].toString() ?? '';
middleName = myRecord[0]["MiddleName"].toString() ?? '';
lastName = myRecord[0]["LastName"].toString() ?? '';
suffix = myRecord[0]["Suffix"].toString() ?? '';
streetNumber = myRecord[0]["StreetNumber"].toString() ?? '';
streetName = myRecord[0]["StreetName"].toString() ?? '';
isLoading = false;
});
}
Example Output
RecordId: 1
FirstName: Bob
MiddleName: E
LastName: Jones
Suffix: Mr
StreetNumber: 123
StreetName: Main St
Thanks for your help!
I tried to display your items from SQLiteMethods.getRecord with recordId from Widget.
I hope this helps.
class YourWidget extends StatefulWidget {
const YourWidget({Key? key, required this.recordId}) : super(key: key);
final int recordId;
#override
State<YourWidget> createState() => _YourWidgetState();
}
class _YourWidgetState extends State<YourWidget> {
List<Map<String, dynamic>> myRecord = [];
final List<String> columnsList = [
'RecordId',
'FirstName',
'MiddleName',
'LastName',
'Suffix',
'StreetNumber',
'StreetName'
];
bool isLoading = false;
#override
void initState() {
super.initState();
fetRecord(widget.recordId);
}
Future<void> fetRecord(int recordId) async {
isLoading = true;
myRecord = await SQLiteMethods.getRecord(recordId);
isLoading = false;
setState(() {});
}
#override
Widget build(BuildContext context) {
if (isLoading) {
return const Center(
child: CircularProgressIndicator(),
);
}
return Column(children: [
for (final record in myRecord)
Container(
color: Colors.black12,
padding: const EdgeInsets.all(10),
child: Column(
children: [for (final key in columnsList) Text('$key: ${record[key]}')],
),
)
]);
}
If you are getting Map from SQLiteMethods.getRecord, then you should do two changes,
List<Map<String, dynamic>> myRecord = []; to Map<String, dynamic> myRecord = {};.
Remove the higher level Column and lower level should be for (final key in columnsList) Text('$key: ${myRecord[key]}')
use this:
Column(children: [for (var i in columnsList) Text("twxt: ${i}")])

How to fix "Unhandled Exception: Null check operator used on a null value" error in flutter?

I'm new to flutter.
I want to pass data from frontend to node.js backend through rest APIs(using post method). But it shows following error when app is executed.
This is the code I wrote so far. I tried to find what the error is, but unfortunately I could not find it. can somebody to help me to figure out this issue?
Model file
DataModel dataModelFromJSON(String str) => DataModel.fromJson(jsonDecode(str));
String dataModelToJson(DataModel data) => json.encode(data.toJson());
class DataModel {
DataModel({required this.title, required this.id});
String title;
String id;
factory DataModel.fromJson(Map<String, dynamic> json) =>
DataModel(title: json['title'], id: json['id']);
Map<String, dynamic> toJson() => {"name": title, "id": id};
}
Error occurred page
class PurchaseOrder extends StatefulWidget {
#override
_PurchaseOrderState createState() => _PurchaseOrderState();
}
Future<DataModel?> submitData(String title) async {
var response = await http.post(
Uri.http('176.12.10.0:8020', 'order/create'),
body: {"title": title},
);
print(title);
var data = response.body;
print(data);
if (response.statusCode == 201) {
String responseString = response.body;
return dataModelFromJSON(responseString);
} else
return null;
}
class _PurchaseOrderState extends State<PurchaseOrder> {
String today = DateFormat('yMd').format(DateTime.now());
late DataModel _dataModel;
TextEditingController titleController = TextEditingController();
#override
Widget build(BuildContext context) {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
return Container(
child: Column(
children: [
TextFormField(
decoration: const InputDecoration(
hintText: 'Enter your email',
),
controller: titleController,
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: OutlinedButton(
onPressed: () async {
String title = titleController.text;
DataModel? data = await submitData(title);
setState(() {
_dataModel = data!;
});
},
child: Text("Submit"),
),
),
),
],
),
);
}
}
I hope your help to fix this issue.
Thank you
Edited:
I did following changes to the code. Error is gone. But data have not passed to the backend. What can I do.
I changed,
_dataModel = data!;
to
if (data != null) {
_dataModel = data;
}
The only null check operator in your code is _dataModel = data!;
That means your submitData method has returned a null value that was passed to data. Or when you put a null check operator you have to make sure the variable isn't null.
To avoid this error you could check if data is null and if true pass another value :
_dataModel = data ?? otherValue
The error means that somewhere in your code you are doing something with a non-nullable type, but the value is actually null.
When you use data! for example, you are telling the compiler that data will not be null, but it actually is.
You could use data ?? someValue to have a fallback, in case data is null.
I could fix "data not passing issue" also.
What I did?
I changed post request from,
var response = await http.post(
Uri.http('176.12.10.0:8020', 'order/create'),
body: {"title": title},
);
to
var response = await http.post(
Uri.parse('http://176.12.10.0:8020/order/create'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({"title": title}),
);

Parsing json to model fails in flutter

I am trying to show data to listview but it doesn't show anything.there is json below ,am i doing something wrong,i tired to print the data in api call but i can print the data but not in the listview,
i having hardtime to understand what i doing wrong or correct.please help me on this
if (response.statusCode == 200) {
try {
if (status == true) {
var company_list = value['doc'];
for (int i = 0; i < company_list.length; i++) {
print(company_list);
var mobile_list = company_list["mobile"];
var email_list = company_list["email"];
company_model.add(CompanyModel.fromJson(company_list,mobile_list,email_list));
}
setState(() {
print("UI Updated");
});
} else {
final snackBar = SnackBar(content: Text(message));
_scaffoldKey.currentState.showSnackBar(snackBar);
}
} catch (e) {
e.toString();
}
} else {
final snackBar = SnackBar(content: Text(message));
_scaffoldKey.currentState.showSnackBar(snackBar);
}
Json
{
"status":true,
"doc":{
"mobile":[
"9961256754",
"8974525672"
],
"email":[
],
"_id":"5f3a0dfe88b9d50453e92133",
"name":"MRC Labour",
"terms":{
"english":"We Shall not be liable for any disputes arising between the users and the
labourers",
"malayalam":"We Shall not be liable for any disputes arising between the users and the
labourers"
}
}
}
Model
class CompanyModel {
String id = "";
String mobile = "";
String email = "";
String name = "";
String english = "";
String malayalam = "";
CompanyModel({this.id, this.mobile, this.email, this.name, this.english,this.malayalam});
CompanyModel.fromJson(json,mobile_list,email_list)
: id = json['_id'].toString(),
mobile = mobile_list,
email = email_list,
name = json['name'].toString(),
english = json['terms']['english'].toString(),
malayalam = json['terms']['malayalam'].toString();
}
When the debugger hit at this line it breaks without any errors company_model.add(CompanyModel.fromJson(data,mobile_list,email_list));
This is listview code
Container(
height: 80,
width: 100,
color: Colors.blueGrey[100],
padding: EdgeInsets.all(10),
child: ListView.separated(
separatorBuilder: (BuildContext context, int index) =>
const Divider(),
itemCount: company_model.length,
itemBuilder: (BuildContext context, int index) {
CompanyModel data = company_model[index];
print(data);
return Container(
height: 10,
color: Colors.green,
child: Text(data.name.toString(),style: TextStyle(color: Colors.black),),
);
},
),
),
First of all, your model is wrong, you're parsing a List (mobile and email) as a String in your model, also, you don't really need to pass 2 additional parameters to the function.
class CompanyModel {
List<String> mobile;
List<String> email;
String sId;
String name;
Terms terms;
CompanyModel({this.mobile, this.email, this.sId, this.name, this.terms});
CompanyModel.fromJson(Map<String, dynamic> json) {
mobile = json['mobile'].cast<String>();
email = json['email'].cast<String>();
sId = json['_id'];
name = json['name'];
terms = json['terms'] != null ? new Terms.fromJson(json['terms']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['mobile'] = this.mobile;
data['email'] = this.email;
data['_id'] = this.sId;
data['name'] = this.name;
if (this.terms != null) {
data['terms'] = this.terms.toJson();
}
return data;
}
}
class Terms {
String english;
String malayalam;
Terms({this.english, this.malayalam});
Terms.fromJson(Map<String, dynamic> json) {
english = json['english'];
malayalam = json['malayalam'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['english'] = this.english;
data['malayalam'] = this.malayalam;
return data;
}
}
Also, double check that you're initializing the company_model as something like: List company_model = [] otherwise it initialize as null and won't work the rest of your code.
if (response.statusCode == 200) {
try {
if (status == true) {
var company_json = value['doc'];
company_model.add(CompanyModel.fromJson(company_json));
setState(() {
print("UI Updated");
});
} else {
final snackBar = SnackBar(content: Text(message));
_scaffoldKey.currentState.showSnackBar(snackBar);
}
} catch (e) {
e.toString();
}
} else {
final snackBar = SnackBar(content: Text(message));
_scaffoldKey.currentState.showSnackBar(snackBar);
}
The best way to create model is in the link below
https://app.quicktype.io/
just put your json on as input on left side and select dart as language from left, you are good to go.

Parse JSON in flutter, show data in label

i have this json:
[
{
"id": 988846211,
"serviceTag": "1LJVKS2",
"orderBuid": 1212,
"shipDate": "2019-04-11T00:00:00Z",
"productCode": ";E403",
"localChannel": "ENTP",
"productId": "dell-u2719d-monitor",
"productLineDescription": "DELL ULTRASHARP U2719D",
"productFamily": "Unknown",
"systemDescription": "Dell U2719D",
"productLobDescription": "Displays",
"countryCode": "SE",
"duplicated": false,
"invalid": false,
"entitlements": [
{
"itemNumber": "709-15308",
"startDate": "2019-04-11T00:00:00Z",
"endDate": "2022-04-11T23:59:59.999Z",
"entitlementType": "INITIAL",
"serviceLevelCode": "ND",
"serviceLevelDescription": "C, NBD ONSITE",
"serviceLevelGroup": 5
},
{
"itemNumber": "865-41964",
"startDate": "2019-04-11T00:00:00Z",
"endDate": "2023-04-11T23:59:59.999Z",
"entitlementType": "INITIAL",
"serviceLevelCode": "ND",
"serviceLevelDescription": "C, NBD ONSITE",
"serviceLevelGroup": 5
}
]
}
]
and my main :
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:dell_warranty/dellTok.dart';
import 'package:dell_warranty/model_json.dart';
void main() => runApp(new MaterialApp(
home: new DellW(),
));
class DellW extends StatefulWidget {
#override
DellWState createState() => new DellWState();
}
class DellWState extends State<DellW> {
TextEditingController serviceTagg = TextEditingController();
final String getToken = "https://apigtwb2c.us.dell.com/auth/oauth/v2/token";
final String apiUrl =
"https://apigtwb2c.us.dell.com/PROD/sbil/eapi/v5/asset-entitlements";
String tagg;
DellTok dellTok;
ModelJson modelJson;
String disc = "";
List<ModelJson> data = [];
#override
void initState() {
super.initState();
this.checkDell();
}
checkDell() async {
var responseToken = await http.post(Uri.encodeFull(getToken), body: {
"grant_type": "client_credentials",
"client_id": "SECRET",
"client_secret": "SECRET"
});
if (responseToken.statusCode == 200) {
var responseTok = json.decode(responseToken.body);
dellTok = DellTok.fromJson(responseTok);
print(responseTok);
setState(() {});
} else {
print(responseToken.statusCode);
}
}
checkDellTagg(String serviceTag) async {
var queryParameters = {
'access_token': dellTok.accessToken,
'servicetags': serviceTag,
};
var uri = Uri.https('apigtwb2c.us.dell.com',
'/PROD/sbil/eapi/v5/asset-entitlements', queryParameters);
var responseDell = await http.get(uri, headers: {});
if (responseDell.statusCode == 200) {
List<dynamic> responseD = jsonDecode(responseDell.body);
List<ModelJson> modelJsonRes =
responseD.map((responseD) => ModelJson.fromJson(responseD)).toList();
setState(() {
disc = modelJson.productLineDescription;
});
} else {
print(responseDell.statusCode);
}
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Dell Warranty"),
),
body: dellTok == null
? Center(
child: CircularProgressIndicator(),
)
: Container(
padding: EdgeInsets.all(20.0),
child: Column(
children: [
RaisedButton(
onPressed: () => checkDellTagg(serviceTagg.text),
child: Text(
"Flat Button",
)),
TextField(
decoration:
InputDecoration(hintText: "write servicetag..."),
controller: serviceTagg,
),
Text(disc),
],
)));
}
}
and my model_json.dart file :
class ModelJson {
int id;
String serviceTag;
int orderBuid;
String shipDate;
String productCode;
String localChannel;
String productId;
String productLineDescription;
String productFamily;
String systemDescription;
String productLobDescription;
String countryCode;
bool duplicated;
bool invalid;
List<Entitlements> entitlements;
ModelJson(
{this.id,
this.serviceTag,
this.orderBuid,
this.shipDate,
this.productCode,
this.localChannel,
this.productId,
this.productLineDescription,
this.productFamily,
this.systemDescription,
this.productLobDescription,
this.countryCode,
this.duplicated,
this.invalid,
this.entitlements});
ModelJson.fromJson(Map<String, dynamic> json) {
id = json['id'];
serviceTag = json['serviceTag'];
orderBuid = json['orderBuid'];
shipDate = json['shipDate'];
productCode = json['productCode'];
localChannel = json['localChannel'];
productId = json['productId'];
productLineDescription = json['productLineDescription'];
productFamily = json['productFamily'];
systemDescription = json['systemDescription'];
productLobDescription = json['productLobDescription'];
countryCode = json['countryCode'];
duplicated = json['duplicated'];
invalid = json['invalid'];
if (json['entitlements'] != null) {
entitlements = new List<Entitlements>();
json['entitlements'].forEach((v) {
entitlements.add(new Entitlements.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['serviceTag'] = this.serviceTag;
data['orderBuid'] = this.orderBuid;
data['shipDate'] = this.shipDate;
data['productCode'] = this.productCode;
data['localChannel'] = this.localChannel;
data['productId'] = this.productId;
data['productLineDescription'] = this.productLineDescription;
data['productFamily'] = this.productFamily;
data['systemDescription'] = this.systemDescription;
data['productLobDescription'] = this.productLobDescription;
data['countryCode'] = this.countryCode;
data['duplicated'] = this.duplicated;
data['invalid'] = this.invalid;
if (this.entitlements != null) {
data['entitlements'] = this.entitlements.map((v) => v.toJson()).toList();
}
return data;
}
}
class Entitlements {
String itemNumber;
String startDate;
String endDate;
String entitlementType;
String serviceLevelCode;
String serviceLevelDescription;
int serviceLevelGroup;
Entitlements(
{this.itemNumber,
this.startDate,
this.endDate,
this.entitlementType,
this.serviceLevelCode,
this.serviceLevelDescription,
this.serviceLevelGroup});
Entitlements.fromJson(Map<String, dynamic> json) {
itemNumber = json['itemNumber'];
startDate = json['startDate'];
endDate = json['endDate'];
entitlementType = json['entitlementType'];
serviceLevelCode = json['serviceLevelCode'];
serviceLevelDescription = json['serviceLevelDescription'];
serviceLevelGroup = json['serviceLevelGroup'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['itemNumber'] = this.itemNumber;
data['startDate'] = this.startDate;
data['endDate'] = this.endDate;
data['entitlementType'] = this.entitlementType;
data['serviceLevelCode'] = this.serviceLevelCode;
data['serviceLevelDescription'] = this.serviceLevelDescription;
data['serviceLevelGroup'] = this.serviceLevelGroup;
return data;
}
}
I'm trying to show the data in text field .
everthing ok when i post to get an access token and its saved and i used it to make a get req to the other url so i can get the data.
example :
i want to show
productLineDescription
in text widget.
but im not going any farther than that!
how i am supposed to get data from model_json.dart and show it inside text widget?
sorry i am flutter newbie, thanks for the help.
If you want to get the productLineDescription, you have to call it like this:
productLineDescription = jsonDecode(myJson)[0]['productLineDescription'];
NOTE: myJson is your json source file.
You need the [0] because your json is inside a List.

How to authenticate the websocket in flutter

I am using Traccar but could not use websocket in Flutter as it is not providing any data.
I think websocket requires authentication or tokens to get the data.
class _HomeState extends State<Home> {
IOWebSocketChannel channel = IOWebSocketChannel.connect("ws://167.172.215.197:8082/api/socket");
#override
Widget build(BuildContext context) {
print(channel);
return new Scaffold(
resizeToAvoidBottomPadding: false,
appBar: AppBar(
title: Text('Map'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// details(),
StreamBuilder(
stream: channel.stream,
builder: (context, snapshot) {
print(snapshot);
return Padding(
padding: const EdgeInsets.symmetric(vertical: 24.0),
child: Container(
child:
Column(
children: <Widget>[
Text(snapshot.hasData ? '${snapshot.data.positions}' : 'No Data'),
],
),
),
);
},
)
],
),
);
}
}
I want to receive the data from the server using websocket in flutter.
yes you need to authenticate and use some variables, for example:
String _cookie;
String _email = "your_email";
String _password = "your_password" ;
final _dio = Dio();
String _cookie;
String serverUrl = "your_server_ip";
StreamSubscription<dynamic> _rawPosSub;
final _devicesMap = <int, Device>{};
final _positions = StreamController<Device>.broadcast();
Future<void> _getConnection({String protocol = "http", String email, String password}) async {
final addr = "$protocol://$serverUrl/api/session";
Map<String, String> body = {
'email' : '$email',
'password': '$password',
};
final response = await Dio().post(addr, data: body,
options: new Options(contentType:"application/x-www-form-urlencoded"));
_cookie = response.headers["set-cookie"][0];
print(_cookie);
}
Next, you should need to create a Device Class (Don't forget to change the project name in the import line of utils)
import 'package:geopoint/geopoint.dart';
import 'package:your_project/utils/utils.dart';
/// A class representing a device
class Device {
/// Main constructor
Device(
{this.id,
this.uniqueId,
this.groupId,
this.name,
this.position,
this.batteryLevel,
this.keepAlive = 1,
this.isActive,
this.isDisabled,
this.properties = const <String, dynamic>{}});
/// The device database id
final int id;
/// The on device unique id
String uniqueId;
/// The group of the device
int groupId;
/// The device name
String name;
/// The device position
DevicePosition position;
/// The device battery level
double batteryLevel;
/// Minutes a device is considered alive
int keepAlive;
/// The device can be disabled
bool isDisabled;
/// false if the device has never updated one position
bool isActive;
/// Extra properties for the device
Map<String, dynamic> properties;
/// Is the device online
bool get isAlive => _isDeviceAlive();
/// Create a device from json data
Device.fromPosition(Map<String, dynamic> data,
{String timeZoneOffset = "0", int keepAlive = 1})
: this.keepAlive = keepAlive,
this.id = int.parse(data["deviceId"].toString()),
this.position =
DevicePosition.fromJson(data, timeZoneOffset: timeZoneOffset),
this.batteryLevel =
double.parse(data["attributes"]["batteryLevel"].toString());
bool _isDeviceAlive() {
if (position == null) {
return false;
}
final now = DateTime.now();
final dateAlive = now.subtract(Duration(minutes: keepAlive));
bool isAlive = false;
if (position.date.isAfter(dateAlive)) {
isAlive = true;
}
return isAlive;
}
/// Print a description of the device
void describe() {
print("Device:");
print(" - id : $id");
print(" - uniqueId : $uniqueId");
print(" - name : $name");
print(" - batteryLevel: $batteryLevel");
print(" - position : $position");
}
#override
String toString() {
String _name = "$uniqueId";
if (name != null) {
_name = name;
}
String res;
if (position != null) {
res = "$_name: $position";
} else {
res = "$_name";
}
return res;
}
}
/// A class to handle a device position
class DevicePosition {
/// The position database id
final int id;
/// The geo data
final GeoPoint geoPoint;
/// The distance since previous point
final double distance;
/// The total distance for the device
final double totalDistance;
/// The address of the device position
final String address;
/// The date of the position
DateTime date;
/// Create a position from json
DevicePosition.fromJson(Map<String, dynamic> data,
{String timeZoneOffset = "0"})
: this.id = int.parse(data["id"].toString()),
this.geoPoint = GeoPoint(
name: data["id"].toString(),
latitude: double.parse(data["latitude"].toString()),
longitude: double.parse(data["longitude"].toString()),
speed: double.parse(data["speed"].toString()),
accuracy: double.parse(data["accuracy"].toString()),
altitude: double.parse(data["altitude"].toString())),
this.distance = double.parse(data["attributes"]["distance"].toString()),
this.totalDistance =
double.parse(data["attributes"]["totalDistance"].toString()),
this.address = data["address"].toString() {
this.date = dateFromUtcOffset(data["fixTime"].toString(), timeZoneOffset);
}
#override
String toString() {
return "$date : ${geoPoint.latitude}, ${geoPoint.longitude}";
}
}
Also you should use a utils method
/// parse a date
DateTime dateFromUtcOffset(String dateStr, String timeZoneOffset) {
DateTime d = DateTime.parse(dateStr);
if (timeZoneOffset.startsWith("+")) {
final of = int.parse(timeZoneOffset.replaceFirst("+", ""));
d = d.add(Duration(hours: of));
} else if (timeZoneOffset.startsWith("-")) {
final of = int.parse(timeZoneOffset.replaceFirst("-", ""));
d = d.subtract(Duration(hours: of));
}
return d;
}
Finally you should need the following methods to listen positions:
/// Get the device positions
Future<Stream<Device>> positions() async {
final posStream =
await _positionsStream(serverUrl: serverUrl, email: _email, password: _password);
_rawPosSub = posStream.listen((dynamic data) {
print("DATA $data");
final dataMap = json.jsonDecode(data.toString()) as Map<String, dynamic>;
if (dataMap.containsKey("positions")) {
DevicePosition pos;
for (final posMap in dataMap["positions"]) {
//print("POS MAP $posMap");
pos = DevicePosition.fromJson(posMap as Map<String, dynamic>);
final id = posMap["deviceId"] as int;
Device device;
if (_devicesMap.containsKey(id)) {
device = _devicesMap[id];
} else {
device = Device.fromPosition(posMap as Map<String, dynamic>,
keepAlive: 1);
}
device.position = pos;
_devicesMap[id] = device;
_positions.sink.add(device);
}
} else {
for (final d in dataMap["devices"]) {
if (!_devicesMap.containsKey(d["id"])) {
final id = int.parse(d["id"].toString());
d["name"] ??= d["id"].toString();
final device = Device(id: id, name: d["name"].toString());
_devicesMap[id] = device;
//print(" - ${device.name}");
}
}
}
});
return _positions.stream;
}
Future<Stream<dynamic>> _positionsStream(
{String serverUrl, String email, String password, String protocol = "http"}) async {
if (_cookie == null) {
await _getConnection(email: _email, password: _password);
}
final channel = IOWebSocketChannel.connect("ws://$serverUrl/api/socket",
headers: <String, dynamic>{"Cookie": _cookie});
return channel.stream;
}
When you finish, you can call
_init() async {
_getConnection(email: _email, password: _password);
final pos = await positions();
print("Listening for position updates");
pos.listen((device) {
print("POSITION UPDATE: $device");
print("${device.id}: ${device.position.geoPoint.latitude} / " +
"${device.position.geoPoint.longitude}");
});
}
Also I use these dependences and flutter version 1.17.0 stable:
dio: ^3.0.9
web_socket_channel:
geopoint: ^0.7.1
Note: I use code from traccar_client 0.1.0 and modify it to access from email and password, but if you need to use the token, you can follow the example from
https://github.com/synw/traccar_client. The credits are to them. :)