I'm building a weather app so I can learn working with API's and Bloc together. So far so good. However I have one problem, how can I access different properties from different classes?
This is my code with the Classes:
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:hava/services/openWeatherMapApi.dart';
import 'package:http/http.dart' as http;
import 'package:geolocator/geolocator.dart';
// To parse this JSON data, do
//
// final getWeatherDetails = getWeatherDetailsFromJson(jsonString);
GetWeatherDetails getWeatherDetailsFromJson(String str) =>
GetWeatherDetails.fromJson(json.decode(str));
String getWeatherDetailsToJson(GetWeatherDetails data) =>
json.encode(data.toJson());
class GetWeatherDetails {
GetWeatherDetails({
required this.cod,
required this.message,
required this.cnt,
required this.list,
required this.city,
});
String cod;
int message;
int cnt;
List<ListElement> list;
String city;
factory GetWeatherDetails.fromJson(Map<String, dynamic> json) =>
GetWeatherDetails(
cod: json["cod"],
message: json["message"],
cnt: json["cnt"],
list: List<ListElement>.from(
json["list"].map((x) => ListElement.fromJson(x))),
city: City.fromJson(json["city"]).toString(),
);
Map<String, dynamic> toJson() => {
"cod": cod,
"message": message,
"cnt": cnt,
"list": List<dynamic>.from(list.map((x) => x.toJson())),
"city": city.toString(),
};
}
class City {
City({
required this.id,
required this.name,
required this.coord,
required this.country,
required this.population,
required this.timezone,
required this.sunrise,
required this.sunset,
});
int id;
String name;
Coord coord;
String country;
int population;
int timezone;
int sunrise;
int sunset;
factory City.fromJson(Map<String, dynamic> json) => City(
id: json["id"],
name: json["name"],
coord: Coord.fromJson(json["coord"]),
country: json["country"],
population: json["population"],
timezone: json["timezone"],
sunrise: json["sunrise"],
sunset: json["sunset"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"coord": coord.toJson(),
"country": country,
"population": population,
"timezone": timezone,
"sunrise": sunrise,
"sunset": sunset,
};
}
class Coord {
Coord({
required this.lat,
required this.lon,
});
double lat;
double lon;
factory Coord.fromJson(Map<String, dynamic> json) => Coord(
lat: json["lat"].toDouble(),
lon: json["lon"].toDouble(),
);
Map<String, dynamic> toJson() => {
"lat": lat,
"lon": lon,
};
}
class ListElement {
ListElement({
required this.dt,
required this.main,
required this.weather,
required this.sys,
required this.dtTxt,
});
int dt;
Main main;
List<Weather> weather;
Sys sys;
DateTime dtTxt;
factory ListElement.fromJson(Map<String, dynamic> json) => ListElement(
dt: json["dt"],
main: Main.fromJson(json["main"]),
weather:
List<Weather>.from(json["weather"].map((x) => Weather.fromJson(x))),
sys: Sys.fromJson(json["sys"]),
dtTxt: DateTime.parse(json["dt_txt"]),
);
Map<String, dynamic> toJson() => {
"dt": dt,
"main": main.toJson(),
"weather": List<dynamic>.from(weather.map((x) => x.toJson())),
"sys": sys.toJson(),
"dt_txt": dtTxt.toIso8601String(),
};
}
class Main {
Main({
required this.temp,
required this.feelsLike,
required this.tempMin,
required this.tempMax,
});
double temp;
double feelsLike;
double tempMin;
double tempMax;
factory Main.fromJson(Map<String, dynamic> json) => Main(
temp: json["temp"].toDouble(),
feelsLike: json["feels_like"].toDouble(),
tempMin: json["temp_min"].toDouble(),
tempMax: json["temp_max"].toDouble(),
);
Map<String, dynamic> toJson() => {
"temp": temp,
"feels_like": feelsLike,
"temp_min": tempMin,
"temp_max": tempMax,
};
}
class Sys {
Sys({
required this.pod,
});
String pod;
factory Sys.fromJson(Map<String, dynamic> json) => Sys(
pod: json["pod"],
);
Map<String, dynamic> toJson() => {
"pod": pod,
};
}
class Weather {
Weather({
required this.id,
required this.main,
required this.description,
required this.icon,
});
int id;
String main;
String description;
String icon;
factory Weather.fromJson(Map<String, dynamic> json) => Weather(
id: json["id"],
main: json["main"],
description: json["description"],
icon: json["icon"],
);
Map<String, dynamic> toJson() => {
"id": id,
"main": main,
"description": description,
"icon": icon,
};
}
class GetWeatherService {
late LocationPermission checkPermission;
late LocationPermission requestPermission;
List coordinatesList = [];
late dynamic latitude;
late dynamic longitude;
//CHECK AND GET LOCATION PERMISSION
Future checkAndGetLocationPermissions() async {
// Check if gps is enabled
bool servicestatus = await Geolocator.isLocationServiceEnabled();
await Geolocator.requestPermission();
await Geolocator.checkPermission();
if (servicestatus) {
if (kDebugMode) {
print("GPS service is enabled");
}
Position position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high);
latitude = position.latitude;
print(latitude);
longitude = position.longitude;
print(longitude);
coordinatesList.add(latitude);
coordinatesList.add(longitude);
if (kDebugMode) {
print(coordinatesList);
}
return coordinatesList;
} else {
if (kDebugMode) {
print("GPS service is disabled.");
}
}
// final response = await http.get(Uri.parse(
// "api.openweathermap.org/data/2.5/forecast?lat=${$position.lattude}&lon=$longitude&appid=$openWeatherMapApiKey"));
// final weatherDetails = getWeatherDetailsFromJson(response.body);
// return weatherDetails;
}
Future<GetWeatherDetails> getWeather() async {
dynamic latLong = await checkAndGetLocationPermissions() as List;
// print(latLong.runtimeType);
print("latLong, $latLong");
double latitude = latLong[0];
double longitude = latLong[1];
final response = await http.get(Uri.parse(
"http://api.openweathermap.org/data/2.5/forecast?lat=$latitude&lon=$longitude&appid=$openWeatherMapApiKey"));
final weatherDetails = getWeatherDetailsFromJson(response.body.toString());
return weatherDetails;
}
}
With the code above I am only able to acces properties from GetWeatherDetails such as 'city'.
I would like to be able to acces other propertes from other classes such as the ones in Classes, Main, City and List Element. How can I achieve this?
I am calling this method getWeather like this (home_bloc.dart):
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:hava/services/weatherService.dart';
part 'home_event.dart';
part 'home_state.dart';
class HomeBloc extends Bloc<HomeEvent, HomeState> {
final GetWeatherService _getWeatherService;
HomeBloc(this._getWeatherService) : super(HomeLoadingState()) {
on<LoadApiEvent>((event, emit) async {
// TODO: implement event handler
emit(HomeLoadingState());
final activity = await _getWeatherService.getWeather();
print(activity.city);
emit(HomeLoadedState(activity.city));
});
}
}
This is the Json Response:
{
"cod": "200",
"message": 0,
"cnt": 40,
"list": [
{
"dt": 1663880400,
"main": {
"temp": 295.86,
"feels_like": 296.33,
"temp_min": 295.86,
"temp_max": 295.86
},
"weather": [
{
"id": 803,
"main": "Clouds",
"description": "broken clouds",
"icon": "04n"
}
],
"dt_txt": "2022-09-22 21:00:00"
},
{
"dt": 1663880400,
"main": {
"temp": 295.86,
"feels_like": 296.33,
"temp_min": 295.86,
"temp_max": 295.86
},
"weather": [
{
"id": 803,
"main": "Clouds",
"description": "broken clouds",
"icon": "04n"
}
],
"dt_txt": "2022-09-22 21:00:00"
}
],
"city": {
"id": 2351027,
"name": "Akko",
"coord": {
"lat": 10.34,
"lon": 10.99
},
"country": "NG",
"population": 6129,
"timezone": 3600,
"sunrise": 1663391140,
"sunset": 1663434946
}
}
I have shortened the above json response to show weather details of 2 days only, but in the actual response it show weather details of 5 days.
The classes were generated in "quicktype" by pasting the json response.
Thank you for any help!
Edit 1: Code above reformatted.
Edit 2:Added Json response code above. I have shortened the above json response to show weather details of 2 days only, but in the actual response it show weather details of 5 days.
The classes were generated in "quicktype" by pasting the json response.
CodePudding user response:
The problem is you are assigning string type to "city" but "city" is City type(which is an object) consist of other attributes.
change this:
class GetWeatherDetails {
GetWeatherDetails({
required this.cod,
required this.message,
required this.cnt,
required this.list,
required this.city,
});
String cod;
int message;
int cnt;
List<ListElement> list;
City city; //here you assigned string but should be City type
factory GetWeatherDetails.fromJson(Map<String, dynamic> json) =>
GetWeatherDetails(
cod: json["cod"],
message: json["message"],
cnt: json["cnt"],
list: List<ListElement>.from(
json["list"].map((x) => ListElement.fromJson(x))),
city: City.fromJson(json["city"]), //here also you are changing it to
string
);
Map<String, dynamic> toJson() => {
"cod": cod,
"message": message,
"cnt": cnt,
"list": List<dynamic>.from(list.map((x) => x.toJson())),
"city": city, //here also you are changing it to string
};
}
class City {
City({
required this.id,
required this.name,
required this.coord,
required this.country,
required this.population,
required this.timezone,
required this.sunrise,
required this.sunset,
});
Now you can access the other property of City class
HomeBloc(this._getWeatherService) : super(HomeLoadingState()) {
on<LoadApiEvent>((event, emit) async {
// TODO: implement event handler
emit(HomeLoadingState());
final activity = await _getWeatherService.getWeather();
print(activity.city.coord.lat);
print(activity.city.name);
// here you can access all
print(activity.city.list[0].main.temp);// you can loop through
the list and get the specific value. I just assigned the
first index
});
}
CodePudding user response:
Use this response
class WeatherOne {
String? cod;
int? message;
int? cnt;
List<WeatherList>? list;
City? city;
WeatherOne({this.cod, this.message, this.cnt, this.list, this.city});
WeatherOne.fromJson(Map<String, dynamic> json) {
cod = json['cod'];
message = json['message'];
cnt = json['cnt'];
if (json['list'] != null) {
list = <WeatherList>[];
json['list'].forEach((v) {
list!.add(new WeatherList.fromJson(v));
});
}
city = json['city'] != null ? new City.fromJson(json['city']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['cod'] = this.cod;
data['message'] = this.message;
data['cnt'] = this.cnt;
if (this.list != null) {
data['list'] = this.list!.map((v) => v.toJson()).toList();
}
if (this.city != null) {
data['city'] = this.city!.toJson();
}
return data;
}
}
class WeatherList {
int? dt;
Main? main;
List<Weather>? weather;
String? dtTxt;
WeatherList({this.dt, this.main, this.weather, this.dtTxt});
WeatherList.fromJson(Map<String, dynamic> json) {
dt = json['dt'];
main = json['main'] != null ? new Main.fromJson(json['main']) : null;
if (json['weather'] != null) {
weather = <Weather>[];
json['weather'].forEach((v) {
weather!.add(new Weather.fromJson(v));
});
}
dtTxt = json['dt_txt'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['dt'] = this.dt;
if (this.main != null) {
data['main'] = this.main!.toJson();
}
if (this.weather != null) {
data['weather'] = this.weather!.map((v) => v.toJson()).toList();
}
data['dt_txt'] = this.dtTxt;
return data;
}
}
class Main {
double? temp;
double? feelsLike;
double? tempMin;
double? tempMax;
Main({this.temp, this.feelsLike, this.tempMin, this.tempMax});
Main.fromJson(Map<String, dynamic> json) {
temp = json['temp'];
feelsLike = json['feels_like'];
tempMin = json['temp_min'];
tempMax = json['temp_max'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['temp'] = this.temp;
data['feels_like'] = this.feelsLike;
data['temp_min'] = this.tempMin;
data['temp_max'] = this.tempMax;
return data;
}
}
class Weather {
int? id;
String? main;
String? description;
String? icon;
Weather({this.id, this.main, this.description, this.icon});
Weather.fromJson(Map<String, dynamic> json) {
id = json['id'];
main = json['main'];
description = json['description'];
icon = json['icon'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['main'] = this.main;
data['description'] = this.description;
data['icon'] = this.icon;
return data;
}
}
class City {
int? id;
String? name;
Coord? coord;
String? country;
int? population;
int? timezone;
int? sunrise;
int? sunset;
City(
{this.id,
this.name,
this.coord,
this.country,
this.population,
this.timezone,
this.sunrise,
this.sunset});
City.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
coord = json['coord'] != null ? new Coord.fromJson(json['coord']) : null;
country = json['country'];
population = json['population'];
timezone = json['timezone'];
sunrise = json['sunrise'];
sunset = json['sunset'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
if (this.coord != null) {
data['coord'] = this.coord!.toJson();
}
data['country'] = this.country;
data['population'] = this.population;
data['timezone'] = this.timezone;
data['sunrise'] = this.sunrise;
data['sunset'] = this.sunset;
return data;
}
}
class Coord {
double? lat;
double? lon;
Coord({this.lat, this.lon});
Coord.fromJson(Map<String, dynamic> json) {
lat = json['lat'];
lon = json['lon'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['lat'] = this.lat;
data['lon'] = this.lon;
return data;
}
}