Flutter API Resulting In Null - api

currently working on a flutter project with API. I'm quite new to flutter,
My Code:
Results null.
Being working on it for quite some time but couldn't find a solution. First, try on a flutter app therefore I'm quite new to this, would appreciate any solutions or tips/resources.
All variables are resulting in null as you can see I tried printing them couldn't figure out why.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
void main() => runApp(MyApp());
Future<Data> getData() async {
final response = await get("https://covid-api.com/api/reports?date=2020-03-25&iso=TUR&region_name=Turkey");
if(response.statusCode == 200) {
return Data.fromJson(jsonDecode(response.body));
} else {
throw Exception('Not Working');
}
}
class Data {
String date;
int confirmed;
int deaths;
int recovered;
int confirmedDiff;
int deathsDiff;
int recoveredDiff;
int active;
int activeDiff;
double fatalityRate;
Data({
this.date,
this.confirmed,
this.deaths,
this.recovered,
this.confirmedDiff,
this.deathsDiff,
this.recoveredDiff,
this.active,
this.activeDiff,
this.fatalityRate,
});
factory Data.fromJson(Map<String, dynamic> json) {
return Data(
confirmed: json['confirmed'],
deaths: json['deaths'],
recovered: json['recovered'],
confirmedDiff: json['confirmed_diff'],
deathsDiff: json['deaths_diff'],
recoveredDiff: json['recovered_diff'],
active: json['active'],
activeDiff: json['active_diff'],
fatalityRate: json['fatality_rate'],
);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['date'] = this.date;
data['confirmed'] = this.confirmed;
data['deaths'] = this.deaths;
data['recovered'] = this.recovered;
data['confirmed_diff'] = this.confirmedDiff;
data['deaths_diff'] = this.deathsDiff;
data['recovered_diff'] = this.recoveredDiff;
data['active'] = this.active;
data['active_diff'] = this.activeDiff;
data['fatality_rate'] = this.fatalityRate;
return data;
}
}
class MyApp extends StatelessWidget {
final Future<Data> data = getData();
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(primaryColor: Colors.red),
home: Scaffold(
appBar: AppBar(title: Text('COVID-19 Turkey')),
body: Center(
child: FutureBuilder<Data>(
future: data,
builder: (context, snapshot) {
print(snapshot.data.deaths);
print('wtf');
print(snapshot.data.deathsDiff);
print(snapshot.data.recovered);
if(snapshot.hasData){
return Text(snapshot.data.confirmed.toString());
} else if (snapshot.hasError) {
return Text('Error');
}
return Center(child: CircularProgressIndicator(),);
},
),)
)
);
}
}

I think the following is the right way of using FutureBuilder:
FutureBuilder(
future: getData(),
builder: (context, snapshot) {
if (!snapshot.hasData
&& snapshot.connectionState != ConnectionState.done) {
return Center(child: CircularProgressIndicator());
}
if(snapshot.hasData) {
return Text(snapshot.data.confirmed.toString());
} else if (snapshot.hasError) {
return Text('Error');
}
});
Hope it helps!

The problem is in your JSON parsing. On this line,
return Data.fromJson(jsonDecode(response.body));
I called your API and it is giving a Map in which there is a data field and then there is a list of objects in it.
Your getData function needs to be like this,
Future<Data> getData() async {
final response = await get("https://covid-api.com/api/reports?date=2020-03-25&iso=TUR&region_name=Turkey");
if(response.statusCode == 200) {
var data = jsonDecode(response.body);
var firstObj = (data['data'] as List<dynamic>).first;
return Data.fromJson(firstObj);
} else {
throw Exception('Not Working');
}
}
Hope this fixes it for you.

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

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 :)
}
}

_TypeError in call api flutter

Good afternoon, I am making a call to my api to bring the businesses that I have registered.
This is my model
class Shops{
Shops({
this.id,
this.name,
this.phone,
this.merchantType,
this.address,
this.city,
this.distance,
this.logo,
});
String id;
String name;
String phone;
String merchantType;
String address;
String city;
double distance;
String logo;
factory Shops.fromJson(Map<String, dynamic> json){
return Shops(
id: json["_id"],
name : json["name"],
phone : json["phone"],
merchantType : json["merchantType"],
address : json["address"],
city : json["city"],
distance : json["distance"].toDouble(),
logo : json["logo"],
);
}
}
Here I make the call
Future<Shops> getShops(var userLatitude, var userLongitude) async {
final response =
await http.get('https://dry-plateau-30024.herokuapp.com/v1/front/merchants?lat=$userLatitude&lng=$userLongitude');
if (response.statusCode == 200) {
return Shops.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load Shops');
}
}
so I show the results
FutureBuilder<Shops>(
future:
getShops(services.userLatitude, services.userLongitude),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data.name);
} else if (snapshot.hasError) {
return Information(
title: 'No results found',
subtitle: 'It seems there is nothing in your area',
img: 'assets/nada.png',
);
} else {
return CircularProgressIndicator();
}
},
)
This returns me the following error
_TypeError (type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>'
I am evolving with the framework and the dart language, I am presented with these errors that perhaps for you are a newbie. I would appreciate a little help
Using the new link for the JSON you have given. Since it is a list we will have to cast it to a list and map through it. Before you were just returning one instance of ShopsFuture<Shops> instead of Future<List<Shops>>
class _CompaniesState extends State<Companies> {
Future<List<Shops>> getShops(var userLatitude, var userLongitude) async {
final response =
await http.get("https://dry-plateau-30024.herokuapp.com/v1/front/merchants?lat=-27.4885846&lng=-58.9509858");
if (response.statusCode == 200) {
// typecasting it into a list
var jsonData = json.decode(response.body) as List;
// Map through it and return it
return jsonData.map((shop) => Shops.fromJson(shop)).toList();
} else {
throw Exception('Failed to load Shops');
}
}
#override
Widget build(BuildContext context) {
return Container(
child: FutureBuilder<List<Shops>>(
future: getShops(12, 20),
builder: (context, snapshot) {
if (snapshot.hasData) {
// Accessing the first map from the list and getting the name key
return Text(snapshot.data[0].name);
} else if (snapshot.hasError) {
return null;
return Information(
title: 'No results found',
subtitle: 'It seems there is nothing in your area',
img: 'assets/nada.png',
);
} else {
return CircularProgressIndicator();
}
},
));
}
}

Flutter: Keep user logged in after app closes and reopen

I'm a beginner and requesting help. I tried to find the answer but sadly cannot find the answer that I'm looking for. I'm building an app where users can see the homepage and other parts of the app when they are not logged in. This part I have working but only when I close the app and restart it I need to log in again. This is of course not ideal. I tried to look for the SharedPreferences but all examples I can find are with a login function for the whole app and I can't figure out how to get it working in my app. Below is the code I have so far. All help is appreciated and thank you all in advance!
(Apologies for posting so much code but it might help!)
Main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:reboo1/services/firebaseauthservice.dart';
import 'package:reboo1/services/users.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return StreamProvider<User>.value(
value: AuthService().user,
child: MaterialApp(
title: 'Rèboo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home:HomePage(),
),
);
}
}
HomePage.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:reboo1/authenticate/signin.dart';
import 'package:reboo1/authenticate/signout.dart';
import 'package:reboo1/models/drawerlogin.dart';
import 'package:reboo1/models/drawerlogout.dart';
import 'package:reboo1/services/firebaseauthservice.dart';
import 'package:reboo1/services/users.dart';
class DrawerItem {
String title;
IconData icon;
DrawerItem(this.title, this.icon);
}
class HomePage extends StatefulWidget {
final drawerItems = [
new DrawerItem("Rèboo", Icons.home),
new DrawerItem("Inbox", Icons.mail_outline),
new DrawerItem("Profile", Icons.person_outline),
new DrawerItem("Reservations", Icons.event_note),
new DrawerItem("Favorites", Icons.favorite_border),
new DrawerItem("Vouchers", Icons.card_giftcard),
new DrawerItem("Invite Friends", Icons.person_add),
new DrawerItem("Settings", Icons.settings),
new DrawerItem("FAQ", Icons.help_outline),
new DrawerItem("Terms & Conditions", Icons.assignment),
new DrawerItem("Sign out", Icons.exit_to_app),
];
#override
State<StatefulWidget> createState() {
return new HomePageState();
}
}
class HomePageState extends State<HomePage> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
int _selectedDrawerIndex = 0;
var _setIcon = Icons.person;
var drawer;
String uid;
_getDrawerItemWidget(int pos) {
switch (pos) {
case 0:
return new Reboo();
case 1:
return new Inbox();
case 2:
return new Profile();
case 3:
return new Reservations();
case 4:
return new Favorites();
case 5:
return new Vouchers();
case 6:
return new InviteFriends();
case 7:
return new Settings();
case 8:
return new Faq();
case 9:
return new TermsAndConditions();
case 10:
return new SignOut();
default:
return new Text("Error");
}
}
_onSelectItem(int index) {
setState(() => _selectedDrawerIndex = index);
if (_selectedDrawerIndex == 0) {
setState(() => _setIcon = Icons.person);
} else {
setState(() => _setIcon = Icons.arrow_back);
}
Navigator.of(context).pop(); // close the drawer
}
#override
Widget build(BuildContext context) {
var drawerOptions = <Widget>[];
for (var i = 0; i < widget.drawerItems.length; i++) {
var d = widget.drawerItems[i];
drawerOptions.add(new ListTile(
leading: new Icon(
d.icon,
color: Color(0xFF008577),
),
title: new Text(d.title),
selected: i == _selectedDrawerIndex,
onTap: () => _onSelectItem(i),
));
}
final auth = Provider.of<User>(context, listen: false);
if (auth != null) {
drawer = DrawerLogin();
} else {
drawer = DrawerLogout();
}
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
leading: Builder(
builder: (BuildContext context) {
return IconButton(
icon: new Icon(_setIcon),
onPressed: () {
if (_selectedDrawerIndex == 0) {
Scaffold.of(context).openDrawer();
} else {
setState(() => _selectedDrawerIndex = 0);
setState(() => _setIcon = Icons.person);
}
},
tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
);
},
),
centerTitle: true,
title: new Text(widget.drawerItems[_selectedDrawerIndex].title),
backgroundColor: Color(0xFF008577),
elevation: 0.0,
actions: <Widget>[
IconButton(
icon: Icon(Icons.menu, color: Colors.white),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Company()),
);
},
)
],
),
drawer: new Drawer(
child: SingleChildScrollView(
child: new Column(
children: <Widget>[drawer, new Column(children: drawerOptions)],
),
),
),
body: _getDrawerItemWidget(_selectedDrawerIndex),
);
}
}
FirebaseAuthService.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:reboo1/services/users.dart';
import 'package:reboo1/services/database.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// create user obj based on FirebaseUser
User _userFromFirebaseUser(FirebaseUser user){
return user != null ? User(uid: user.uid) : null;
}
// auth change user stream
Stream<User> get user {
return _auth.onAuthStateChanged
.map(_userFromFirebaseUser);
}
// sign with email & password
Future signInWithEmailAndPassword(String email, String password) async {
try {
AuthResult result = await _auth.signInWithEmailAndPassword(email: email, password: password);
FirebaseUser user = result.user;
return _userFromFirebaseUser(user);
}catch(e){
print(e.toString());
return null;
}
}
// register with email & password
Future registerForm(String email, String password, String birthday, String address, String fullName, String phone) async {
try {
AuthResult result = await _auth.createUserWithEmailAndPassword(email: email, password: password);
FirebaseUser user = result.user;
// creat a new document in the database for the user with the uid
await DatabaseService(uid: user.uid).updateUserData(email, birthday, address, fullName, phone);
return _userFromFirebaseUser(user);
}catch(e){
print(e.toString());
return null;
}
}
Stream<String> get onAuthStateChanged =>
_auth.onAuthStateChanged.map(
(FirebaseUser user) => user?.uid,
);
// GET UID
Future<String> getCurrentUID() async {
return (await _auth.currentUser()).uid;
}
Future getCurrentUser() async {
return await _auth.currentUser();
}
//sign out
Future signOut() async{
try{
return await _auth.signOut();
}catch(e){
print(e.toString());
return null;
}
}
}
SignIn.dart
import 'package:flutter/material.dart';
import 'package:reboo1/authenticate/register.dart';
import 'package:reboo1/home/homepage.dart';
import 'package:reboo1/services/constants.dart';
import 'package:reboo1/services/loading.dart';
import 'package:reboo1/services/firebaseauthservice.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SignIn extends StatefulWidget {
final Function toggleView;
SignIn({this.toggleView});
#override
_SignInState createState() => _SignInState();
}
class _SignInState extends State<SignIn> {
final AuthService _auth = AuthService();
final _formKey = GlobalKey<FormState>(); //global key
bool loading = false;
// text field state
String email = '';
String password = '';
String error = '';
#override
Widget build(BuildContext context) {
return loading
? Loading()
: Scaffold(
backgroundColor: Colors.brown[50],
appBar: AppBar(
backgroundColor: Color(0xFF008577),
elevation: 0.0,
title: Text('Sign in to Rèboo'),
actions: <Widget>[
FlatButton.icon(
textColor: Colors.white,
icon: Icon(Icons.person),
label: Text('Register'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Register()),
);
},
)
],
),
body: Container(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 50.0),
child: Form(
key: _formKey, //global key
child: Column(children: <Widget>[
SizedBox(height: 20.0),
TextFormField(
decoration: textInputDecoration.copyWith(
hintText: 'Email address'),
validator: (val) =>
val.isEmpty ? 'Enter an email address' : null,
onChanged: (val) {
setState(() => email = val);
}),
SizedBox(height: 20.0),
TextFormField(
decoration:
textInputDecoration.copyWith(hintText: 'Password'),
validator: (val) =>
val.length < 8 ? 'Enter valid password' : null,
obscureText: true,
onChanged: (val) {
setState(() => password = val);
},
),
SizedBox(height: 20.0),
RaisedButton(
color: Colors.purple[400],
child:
Text('Sign in', style: TextStyle(color: Colors.white)),
onPressed: () async {
if (_formKey.currentState.validate()) {
setState(() => loading = true);
dynamic result = await _auth.signInWithEmailAndPassword(
email, password);
if (result == null) {
setState(() {
error =
'Could not sign in with those credentials. Please register an account.';
setState(() => loading = false);
});
} else {
setState(() => loading = false);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
}
}
},
),
SizedBox(height: 12.0),
Text(
error,
style: TextStyle(color: Colors.red, fontSize: 14.0),
)
]),
),
),
);
}
}
Have provided a dummy implementation but this is the legit way to tackle this. If you want to search on google, search for keyword firebase onAuthChanged, and read about it. No local storage is required and the most simple and secure way to handle your requirement.
StreamBuilder<FirebaseUser>(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (BuildContext context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return print("getting data");
} else if (snapshot.connectionState == ConnectionState.active &&
!snapshot.hasData) {
return print("no user found");
} else if (snapshot.connectionState == ConnectionState.active &&
snapshot.hasData)
{
return print(snapshot.data.currentuser);
}
else
return null;
},
You could save some sort of data to your shared preferences, then when a user opens the app you could retrieve that data from the shared preferences to determine if the user should already be logged in or not. That data could be the users bearer token and expiry date for instance. This could look something like this:
Save data to shared preferences:
Future storeTokenPropertiesToPreferences(
TokenProperties accessTokenProperties, refreshTokenProperties) async {
final preferences = await SharedPreferences.getInstance();
preferences.setString(
_preferencesLocation,
json.encode(
{
'accessToken': accessTokenProperties?.value,
'refreshToken': refreshTokenProperties?.value,
'accessTokenExpiresAt':
accessTokenProperties?.expiresAt?.toIso8601String(),
'refreshTokenExpiresAt':
refreshTokenProperties?.expiresAt?.toIso8601String(),
},
),
);
Retrieve data:
Future<TokenProperties> _tokenPropertiesFromPreferences(
String tokenName) async {
final _userData = await _getPreferences();
try {
final value = _userData[tokenName];
final expiresAt = DateTime.parse(_userData['${tokenName}ExpiresAt']);
final lifeTime = expiresAt.difference(DateTime.now()).inSeconds;
return (value == null || expiresAt == null)
? null
: TokenProperties(value, lifeTime);
} catch (e) {
await _loggingService.log(LoggingMethod.ERROR,
'Could not get token properties from preferences for token $tokenName. Got exception: $e');
return null;
}
Future<Map<String, Object>> _getPreferences() async {
final preferences = await SharedPreferences.getInstance();
if (!preferences.containsKey(_preferencesLocation)) return null;
return json.decode(preferences.getString(_preferencesLocation))
as Map<String, Object>;
}
You could obviously change out the object properties to whatever you need, this is just an example.
I don't think you need to mess up with local storage to save user's detail.As Firebase itself store user's detail in local storage.You just need to call .currentUser() method of FirebaseAuth class object when your app starts. If the current user is null then load Login Page otherwise your Main Page. Just like that;
Future loadUser() async {
FirebaseUser _tempUser = await _auth.currentUser();
if (_tempUser != null)
// goto MainPage(mainUser:_tempUser);
} else
// goto LoginPage;
}
thanks to #UTKARSH Sharma I found out that the user is not logged out but the problem was in my own code. I found the below code which helped me solve my problem:
#override
void initState() {
super.initState();
var auth = FirebaseAuth.instance;
auth.onAuthStateChanged.listen((user) {
if (user != null) {
print("user is logged in");
//navigate to home page using Navigator Widget
} else {
print("user is not logged in");
//navigate to sign in page using Navigator Widget
}
});
}
Thank you everyone for your help!

Flutter FutureBuilder returning null data

I'm new to Flutter and Dart, and I'm trying to write a application to test it.
I have an api that I'm getting the data for the app, and was trying to use the StatefulWidget and the FutureBuilder.
When I run the method to call the api I have the results (used print() to test it), but when I get the data from loadData method it retrives null.
So loadData prints the data, initState and FutureBuilder the data returns null. What am I missing here.
I have added the service and the models used for the request... hope it help.
Future<CoachesModelRes> loadData(Profile _profile) async {
await getPost(_profile.getToken()).then((response) {
if (response.statusCode == 200) {
CoachesModelRes coaches = coachesModel.postFromJson(response.body);
if (coaches.count > 0) {
print(coaches.count);
print(coaches.coaches[0].description);
return coaches;
} else {
return null;
}
} else {
String code = response.statusCode.toString();
return null;
}
}).catchError((error) {
print(error.toString());
return null;
});
}
#override
void initState() {
super.initState();
print(widget.profile.getToken());
data = loadData(widget.profile);
data.then((data_) async {
var cenas = data_.count;
print("asdasd $cenas");
});
}
Future<CoachesModelRes> data;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: appWhiteColor,
appBar: applicationBar(),
drawer: adminDrawer(widget.profile, AdminDrawerListEnum.coaches, context),
body: FutureBuilder<CoachesModelRes>(
future: data,
builder: (context, snapshot) {
//print(snapshot.data.count.toString());
if (snapshot.hasData) {
return Text("nop");
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return Text("nop");
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
);
}
Future<http.Response> getPost(String token) async {
final response = await http.get(new Uri.http("$apiUrl", "$coachesEndPoint"),
headers: {
HttpHeaders.contentTypeHeader: 'application/json',
HttpHeaders.authorizationHeader : 'Bearer $token'
},
);
return response;
}
CoachesModelRes postFromJson(String str) => CoachesModelRes.fromJson(json.decode(str));
class CoachesModelRes {
int count;
List<CoachModelRes> coaches;
CoachesModelRes({
this.count,
this.coaches,
});
factory CoachesModelRes.fromJson(Map<String, dynamic> json) => new CoachesModelRes(
count: json["count"],
coaches: (json["coaches"] as List).map((i) => CoachModelRes.fromJson(i)).toList(),
);
}
CoachModelRes postFromJson(String str) => CoachModelRes.fromJson(json.decode(str));
class CoachModelRes {
String id;
String firstName;
String lastName;
String description;
String username;
String notes;
List<String> roles;
CoachModelRes({
this.id,
this.firstName,
this.lastName,
this.description,
this.username,
this.notes,
this.roles,
});
factory CoachModelRes.fromJson(Map<String, dynamic> json) => new CoachModelRes(
id: json["id"],
firstName: json["firstName"],
lastName: json["lastName"],
description: json["description"],
username: json["username"],
notes: json["notes"],
roles: new List<String>.from(json["roles"]),
);
}
Future<CoachesModelRes> loadData(Profile _profile) async {
final response = await getPost(_profile.getToken());
try{if (response.statusCode == 200) {
CoachesModelRes coaches = coachesModel.postFromJson(response.body);
if (coaches.count > 0) {
print(coaches.count);
print(coaches.coaches[0].description);
return coaches;
} else {
return null;
}
} else {
String code = response.statusCode.toString();
return null;
}}catch(e){
return null ;
}
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: appWhiteColor,
appBar: applicationBar(),
drawer: adminDrawer(widget.profile, AdminDrawerListEnum.coaches, context),
body: FutureBuilder<CoachesModelRes>(
future: loadData(widget.profile),
builder: (context, snapshot) {
//print(snapshot.data.count.toString());
if (snapshot.hasData) {
return Text("nop");
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return Text("nop");
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
);
}
The issue here is that the return statement should be at the end of the method.
Because the getPost will return data to the loadData.
And when the getPost finishes the loadData will return data to the method that invoked him.
In my case, the loadData is not returning anything so the snapshot in the FutureBuilder it's always null.
It's logic that it is this way now, but at the time I could not figure it out :\
Future<CoachesModelRes> loadData(Profile _profile) async {
// So I need to create a variable to return
CoachesModelRes response;
//-----
await getPost(_profile.getToken()).then((response) {
if (response.statusCode == 200) {
CoachesModelRes coaches = coachesModel.postFromJson(response.body);
if (coaches.count > 0) {
print(coaches.count);
print(coaches.coaches[0].description);
// Set the variable value
response = coaches;
//-----
} else {
// Set the variable value
response = null;
//-----
}
} else {
String code = response.statusCode.toString();
// Set the variable value
response = null;
//-----
}
}).catchError((error) {
print(error.toString());
// Set the variable value
response = null;
//-----
});
// And at the end return the response variable
return response;
//-----
}