How to put an if statement in another one in flutter? - flutter

I am trying to put an if statement inside another like this :
void initState() {
super.initState();
FirebaseAuth.instance.currentUser().then((res) {
if (res != null) {
if (userType.text == 'Student') {
Navigator.pushReplacementNamed(context, '/StudentsPage');
} else if (userType.text == 'Teacher') {
Navigator.pushReplacementNamed(context, '/TeacherPage');
} else if (userType.text == 'Admin') {
Navigator.pushReplacementNamed(context, '/AdminPage');
}
} else {
LoginScreen();
}
});
}
But It gives me this error that there is a text that was called on null, so if anyone has an idea.
I'm using FireBase database.. and I am retrieving the data using this:
void getUserData() async {
try {
firestoreInstance .collection('Users') .document(usernameController.text) .get() .then((value) {
setState(() {
email = (value.data)['email'];
password = (value.data)['password'];
gender = (value.data)['gender'];
username = (value.data)['username'];
userType = (value.data)['userType'];
}); });
print('$userType');
}
catch (e) {
print(e.toString);
} }

The issue is that userType is a String object and therefore has no text getter method. Remove the .text and it seems that your code would work fine.
if (res != null) {
if (userType == 'Student') {
Navigator.pushReplacementNamed(context, '/StudentsPage');
} else if (userType == 'Teacher') {
Navigator.pushReplacementNamed(context, '/TeacherPage');
} else if (userType == 'Admin') {
Navigator.pushReplacementNamed(context, '/AdminPage');
}
}

Related

Why do I get an error when I log out with Firebase Auth?

this is my logout code:
onPressed: () async {
await FirebaseAuth.instance.signOut();
await widget.checkLogin();
},
This is my CheckLogin function:
checkLogin() async {
if (FirebaseAuth.instance.currentUser != null) {
login = true;
setState(() {});
} else {
login = false;
setState(() {});
}
}
The error it gives me after logging out is the following:
Unhandled Exception: [firebase_database/permission-denied] Client doesn't have permission to access the desired data.
With various attempts I realized that the problem lies in these lines of code, but I don't know how to fix ...
if (FirebaseAuth.instance.currentUser != null) {
WidgetsBinding.instance.addPostFrameCallback((_) async {
DatabaseReference ref = FirebaseDatabase.instance.ref("temp");
if (FirebaseAuth.instance.currentUser != null) {
ref.onValue.listen((DatabaseEvent event) {
final snapshot = event.snapshot.value;
if (snapshot != null) {
Object? temp = snapshot;
if (mounted) {
setState(() {});
}
}
});
}
});
}
Anyone know how to fix?
Go to Your Firebase Console And Update your rules like this
Select Database From Side Menu --> Select Rule From tabs above --> Update your rule like this
{
"rules": {
".read": true,
".write": true
}
}

The return type 'SignUpScreen' isn't a 'void', as required by the closure's context

I'm trying to build a funtion who return Widget for persiting state but I am getting this error.
Future<Widget?> persiting () async {
await FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
if (user == null) {
return SignUpScreen() ;
} else {
return HomeScreen() ;
}
});
}
try this:
Future<Widget?> persiting () async {
late bool hasUsers;
await FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
if (user == null) {
hasUsers = true;
} else {
hasUsers = false;
}
});
return hasUsers ? SignUpScreen() : HomeScreen();
}
The exception showed because you are returning onject to the .listen() function instead of the persiting() function.
What you need to do is await to listen the stream inside the presiting() function.
Future<Widget?> persiting () async {
try{
Stream<User?> stream = await FirebaseAuth.instance
.authStateChanges();
bool hasUser = false;
await stream.forEach((user){
hasUser = user != null;
});
return hasUser? HomeScreen() : SignUpScreen();
}catch(e){
/// better do some handling if any network or unexpected error here
}
}

Good and scalable method to create network client and make network call in flutter

I am working on a large project which requires lot of network calls. Right now I have created a WebApiClass and here I have written my entire app network calls. But I don't think this is the right way.
Sample Code
class WebApiCall{
Dio _dio = Dio();
Dio get dio {
_dio.options.baseUrl = BASE_URL;
_dio.options.headers = {'token': '$tokenKey'};
return _dio;
}
//I have written more than 100 networks calls like this in this class
Future<List<CompletedSessionData>?> getSessionData(int id) async{
List<CompletedSessionData>? completedSessionsData;
try{
final response = await dio.post('path', data: {'id': id});
if(response.statusCode == 200){
//Codes for decoding
}
} catch (e){
print(e);
}
return completedSessionsData;
}
}
I create a dependency injection with provider of this class to use it everywhere in my app
I want to refactor my code and instead of writing all my network call in one class I want to divide in multiple class but I don't want to create multiple Dio client and provide my base URL and toke multiple times.
Please suggest me some good and scalable method for solving my problem.
Thanks
I wrote this some time ago which basically is a service for all types of calls needed using generic types:
class APIService {
APIService(this.baseUrl, this.token) {
_dio = Dio(BaseOptions(baseUrl: baseUrl));
_dio.options.headers["Authorization"] = "Bearer $token";
}
final String token;
final String baseUrl;
var _dio;
Future<T> get<T>(
{required String path,
T Function(Map<String, dynamic> json)? builder,
Map<String, dynamic>? query}) async {
try {
final response = await _dio.get(path, queryParameters: query);
return builder != null ? builder(response.data) : response.data;
} on DioError catch (e) {
debugPrint(e.message);
if (e.type == DioErrorType.other) {
throw SocketException(e.message);
} else if (e.type == DioErrorType.connectTimeout ||
e.type == DioErrorType.receiveTimeout ||
e.type == DioErrorType.sendTimeout) {
throw TimeoutException(e.message);
} else if (e.type == DioErrorType.response) {
throw HttpException(e.response != null ? e.response!.data.toString() : e.message);
} else {
rethrow;
}
}
}
Future<T> getValue<T>(
{required String path,
T Function(dynamic data)? builder,
Map<String, dynamic>? query}) async {
try {
final response = await _dio.get(path, queryParameters: query);
return builder != null ? builder(response.data) : response.data;
} on DioError catch (e) {
debugPrint(e.message);
if (e.type == DioErrorType.other) {
throw SocketException(e.message);
} else if (e.type == DioErrorType.connectTimeout ||
e.type == DioErrorType.receiveTimeout ||
e.type == DioErrorType.sendTimeout) {
throw TimeoutException(e.message);
} else if (e.type == DioErrorType.response) {
throw HttpException(e.response != null ? e.response!.data.toString() : e.message);
} else {
rethrow;
}
}
}
Future<List<T>> getAll<T>(
{required String path,
required List<T> Function(List<dynamic> json) builder,
Map<String, dynamic>? query}) async {
try {
final response = await _dio.get(path, queryParameters: query);
return builder(response.data);
} on DioError catch (e) {
debugPrint(e.message);
if (e.type == DioErrorType.other) {
throw SocketException(e.message);
} else if (e.type == DioErrorType.connectTimeout ||
e.type == DioErrorType.receiveTimeout ||
e.type == DioErrorType.sendTimeout) {
throw TimeoutException(e.message);
} else if (e.type == DioErrorType.response) {
throw HttpException(e.response != null ? e.response!.data.toString() : e.message);
} else {
rethrow;
}
}
}
Future<T> post<T, I>(
{required String path,
I? data,
T Function(Map<String, dynamic> json)? builder}) async {
try {
final response = await _dio.post(path, data: data);
return builder != null ? builder(response.data) : response.data;
} on DioError catch (e) {
debugPrint(e.message);
if (e.type == DioErrorType.other) {
throw SocketException(e.message);
} else if (e.type == DioErrorType.connectTimeout ||
e.type == DioErrorType.receiveTimeout ||
e.type == DioErrorType.sendTimeout) {
throw TimeoutException(e.message);
} else if (e.type == DioErrorType.response) {
throw HttpException(e.response != null ? e.response!.data.toString() : e.message);
} else {
rethrow;
}
}
}
Future<T> patch<T, I>(
{required String path,
I? data,
T Function(Map<String, dynamic> json)? builder}) async {
try {
final response = await _dio.patch(path, data: data);
return builder != null ? builder(response.data) : response.data;
} on DioError catch (e) {
debugPrint(e.message);
if (e.type == DioErrorType.other) {
throw SocketException(e.message);
} else if (e.type == DioErrorType.connectTimeout ||
e.type == DioErrorType.receiveTimeout ||
e.type == DioErrorType.sendTimeout) {
throw TimeoutException(e.message);
} else if (e.type == DioErrorType.response) {
throw HttpException(e.response != null ? e.response!.data.toString() : e.message);
} else {
rethrow;
}
}
}
Future<T> delete<T, I>(
{required String path,
I? data,
T Function(Map<String, dynamic> json)? builder}) async {
try {
final response = await _dio.delete(path, data: data);
return builder != null ? builder(response.data) : response.data;
} on DioError catch (e) {
debugPrint(e.message);
if (e.type == DioErrorType.other) {
throw SocketException(e.message);
} else if (e.type == DioErrorType.connectTimeout ||
e.type == DioErrorType.receiveTimeout ||
e.type == DioErrorType.sendTimeout) {
throw TimeoutException(e.message);
} else if (e.type == DioErrorType.response) {
throw HttpException(e.response != null ? e.response!.data.toString() : e.message);
} else {
rethrow;
}
}
}
}
Then I would use it like this inside my repo implementation:
#override
Future<List<Ticket>>? getTickets({int? offset, int? state, String? query}) {
return _service.getAll(
path: APIPath.tickets(offset: offset, state: state, query: query),
builder: Ticket.ticketsFromJson);
}
#override
Future<Ticket>? getTicket(String id) {
return _service.get(
path: APIPath.ticket(id), builder: (data) => Ticket.fromJson(data));
}

Future<bool> function returns null value flutter

Before posting I took at look at previous questions (because there are many) but I didn't find something that suited my needs.
I have a function that checks if a document exists or not on Firestore, then if the document exists the function must return false, otherwise if not exists, true.
The problem is that the return of the function is always null and also compiler told me that the function doesn't have a return statement but I don't understand why.
This is the code, the important function is checkMissingId the other one just checks if the string id has a valid format or not.
Code :
bool checkStr(String id, String letter, String str) {
if (id.length < 1) {
print("Id is too short");
return false;
} else {
if ('a'.codeUnitAt(0) > letter.codeUnitAt(0) ||
'z'.codeUnitAt(0) < letter.codeUnitAt(0)) {
print("User name begins with bad word!");
return false;
}
print("ids/tabs/" + letter);
return true;
}
}
Future<bool> checkMissingId(String id, context) async {
String str = id.toLowerCase();
String letter = str[0];
if (checkStr(id, letter, str) == false)
return false; //checks some rules on strings
else {
try {
await FirebaseFirestore.instance.collection("ids/tabs/" + letter).doc(str).get()
.then((DocumentSnapshot documentSnapshot) { //Maybe here!(??)
if (documentSnapshot.exists) {
print("Document exists!");
return false;
} else {
print('Document does not exist on the database');
return true;
}
});
} catch (e) {
await showErrDialog(context, e.code);
return false;
}
}
}
The problem is that you are using both await and .then() for getting data from Firestore. Replace your function with this to get desired result:
Future<bool> checkMissingId(String id, context) async {
String str = id.toLowerCase();
String letter = str[0];
if (checkStr(id, letter, str) == false) return false; //checks some rules on strings
else {
try {
DocumentSnapshot documentSnapshot = await FirebaseFirestore.instance.collection("ids/tabs/" + letter).doc(str).get();
if (documentSnapshot.exists) {
print("Document exists!");
return false;
} else {
print('Document does not exist on the database');
return true;
}
} catch (e) {
await showErrDialog(context, e.code);
return false;
}
}
}
Try this:
Future<bool> checkMissingId(String id, context) async {
String str = id.toLowerCase();
String letter = str[0];
if (checkStr(id, letter, str) == false)
return false; //checks some rules on strings
else {
try {
var data = await FirebaseFirestore.instance.collection("ids/tabs/" + letter).doc(str).get()
if (data.exists) {
print("Document exists!");
return false;
} else {
print('Document does not exist on the database');
return true;
}
} catch (e) {
await showErrDialog(context, e.code);
return false;
}
}
}
The problem was that in the .then(...) function, it takes a function as input. So, you wouldn't be able to return anything. Because it doesn't return data to your function.

Flutter how to check Internet connection is available or not

I am trying to use this plugin https://pub.dev/packages/connectivity/example Issue is its not showing or print internet is connected or not.
This is my code
class _HomePageState extends State<HomePage> {
String _connectionStatus = 'Unknown';
final Connectivity _connectivity = Connectivity();
StreamSubscription<ConnectivityResult> _connectivitySubscription;
#override
void initState() {
super.initState();
initConnectivity();
_connectivitySubscription =
_connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
if (mounted) {
if (userManager.getCurrentDriver() != null &&
userManager.getCurrentDriver().isNotEmpty) {
FirebaseFirestore.instance
.collection(FIREBASE_PATH_TRIP)
.doc(userManager.getCurrentDriver())
.get()
.then((event) {
if (event != null) {
var trip =
DriverModel.fromMap(Map<String, dynamic>.from(event.data()));
Provider.of<TripState>(context, listen: false).driver = trip;
Provider.of<BottomSheetSelector>(context, listen: false)
.changeSheet(SheetType.Profile);
} else {
userManager.saveCurrentDriver('');
}
});
}
if (Theme.of(context).platform == TargetPlatform.android) {
checkForAndroidUpdate(context);
}
}
});
}
#override
void dispose() {
_connectivitySubscription.cancel();
super.dispose();
}
Future<void> initConnectivity() async {
ConnectivityResult result;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
result = await _connectivity.checkConnectivity();
} on PlatformException catch (e) {
print(e.toString());
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) {
return Future.value(null);
}
return _updateConnectionStatus(result);
}
#override
Widget build(BuildContext context) {
final _drawerKey = GlobalKey<ScaffoldState>();
ScreenUtil.init(context);
return SafeArea(
child: WillPopScope(
child: Scaffold(
key: _drawerKey,
backgroundColor: Colors.black,
resizeToAvoidBottomInset: false,
drawer: ViteDrawer(),
body: null,
),
));
}
Future<void> _updateConnectionStatus(ConnectivityResult result) async {
switch (result) {
case ConnectivityResult.wifi:
case ConnectivityResult.mobile:
case ConnectivityResult.none:
setState(() => _connectionStatus = result.toString());
break;
default:
setState(() => _connectionStatus = 'Failed to get connectivity.');
break;
}
}
}
What i need to do is simple print if internet is connected or not. I want to show alert but print is ok so ill manage it. But dont know why its not printing anything
You can try with this
Future<bool> check() async {
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile) {
print("Connected}");
return true;
} else if (connectivityResult == ConnectivityResult.wifi) {
print("Connected}");
return true;
}
print("not Connected}");
// return You can add your dialog for notify user to your connectivity is off
}
you can use below code to check the connectivity
Future<bool> checkInternetConnectivity() async {
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
return true;
} else {
return false;
}
} on SocketException catch (_) {
return false;
}
}
simple
Future<bool> isConnected() async {
var result = await Connectivity().checkConnectivity();
return result != ConnectivityResult.none;
}